代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2017 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package timeutil_test
import (
"strings"
"testing"
"time"
. "gopkg.in/check.v1"
"gitee.com/mysnapcore/mysnapd/timeutil"
)
func Test(t *testing.T) { TestingT(t) }
type timeutilSuite struct{}
var _ = Suite(&timeutilSuite{})
func (ts *timeutilSuite) TestClock(c *C) {
td := timeutil.Clock{Hour: 23, Minute: 59}
c.Check(td.Add(time.Minute), Equals, timeutil.Clock{Hour: 0, Minute: 0})
td = timeutil.Clock{Hour: 5, Minute: 34}
c.Check(td.Add(time.Minute), Equals, timeutil.Clock{Hour: 5, Minute: 35})
td = timeutil.Clock{Hour: 10, Minute: 1}
c.Check(td.Sub(timeutil.Clock{Hour: 10, Minute: 0}), Equals, time.Minute)
td = timeutil.Clock{Hour: 23, Minute: 0}
c.Check(td.Add(time.Hour), Equals, timeutil.Clock{Hour: 0, Minute: 0})
c.Check(td.Add(2*time.Hour), Equals, timeutil.Clock{Hour: 1, Minute: 0})
c.Check(td.Sub(timeutil.Clock{Hour: 1, Minute: 0}), Equals, 22*time.Hour)
c.Check(td.Sub(timeutil.Clock{Hour: 0, Minute: 0}), Equals, 23*time.Hour)
td = timeutil.Clock{Hour: 1, Minute: 0}
c.Check(td.Sub(timeutil.Clock{Hour: 23, Minute: 0}), Equals, -2*time.Hour)
c.Check(td.Sub(timeutil.Clock{Hour: 1, Minute: 0}), Equals, time.Duration(0))
td = timeutil.Clock{Hour: 0, Minute: 0}
c.Check(td.Sub(timeutil.Clock{Hour: 23, Minute: 0}), Equals, -1*time.Hour)
c.Check(td.Sub(timeutil.Clock{Hour: 1, Minute: 0}), Equals, -23*time.Hour)
}
func (ts *timeutilSuite) TestParseClock(c *C) {
for _, t := range []struct {
timeStr string
hour, minute int
errStr string
}{
{"8:59", 8, 59, ""},
{"08:59", 8, 59, ""},
{"12:00", 12, 0, ""},
{"xx", 0, 0, `cannot parse "xx"`},
{"11:61", 0, 0, `cannot parse "11:61"`},
{"25:00", 0, 0, `cannot parse "25:00"`},
} {
ti, err := timeutil.ParseClock(t.timeStr)
if t.errStr != "" {
c.Check(err, ErrorMatches, t.errStr)
} else {
c.Check(err, IsNil)
c.Check(ti.Hour, Equals, t.hour)
c.Check(ti.Minute, Equals, t.minute)
}
}
}
func (ts *timeutilSuite) TestScheduleString(c *C) {
for _, t := range []struct {
sched timeutil.Schedule
str string
}{
{
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 13, Minute: 41}, End: timeutil.Clock{Hour: 14, Minute: 59}}},
},
"13:41-14:59",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 13, Minute: 41}, End: timeutil.Clock{Hour: 14, Minute: 59}},
},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
},
"mon,13:41-14:59",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 13, Minute: 41}, End: timeutil.Clock{Hour: 14, Minute: 59}, Spread: true}},
},
"13:41~14:59",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 6}, End: timeutil.Clock{Hour: 6}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Friday}}},
},
"mon-fri,06:00",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 6}, End: timeutil.Clock{Hour: 6}},
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 14}, Spread: true, Split: 2}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Friday}},
{Start: timeutil.Week{Weekday: time.Saturday}, End: timeutil.Week{Weekday: time.Saturday}}},
},
"mon-fri,sat,06:00,09:00~14:00/2",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 6}, End: timeutil.Clock{Hour: 6}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday, Pos: 1}, End: timeutil.Week{Weekday: time.Friday, Pos: 1}}},
},
"mon1-fri1,06:00",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 6}, End: timeutil.Clock{Hour: 6}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday, Pos: 5},
End: timeutil.Week{Weekday: time.Monday, Pos: 5}}},
},
"mon5,06:00",
}, {
timeutil.Schedule{
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
},
"mon",
}, {
timeutil.Schedule{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 6}, End: timeutil.Clock{Hour: 9}, Spread: true, Split: 2}},
},
"06:00~09:00/2",
},
} {
c.Check(t.sched.String(), Equals, t.str)
}
}
func (ts *timeutilSuite) TestParseLegacySchedule(c *C) {
for _, t := range []struct {
in string
expected []*timeutil.Schedule
errStr string
}{
// invalid
{"", nil, `cannot parse "": not a valid interval`},
{"invalid-11:00", nil, `cannot parse "invalid": not a valid time`},
{"9:00-11:00/invalid", nil, `cannot parse "invalid": not a valid interval`},
{"09:00-25:00", nil, `cannot parse "25:00": not a valid time`},
{"09:00-24:30", nil, `cannot parse "24:30": not a valid time`},
// valid
{"9:00-11:00", []*timeutil.Schedule{
{ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}, Spread: true}}},
}, ""},
{"9:00-11:00/20:00-22:00", []*timeutil.Schedule{
{ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}, Spread: true}}},
{ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 20}, End: timeutil.Clock{Hour: 22}, Spread: true}}},
}, ""},
} {
c.Logf("trying: %v", t)
schedule, err := timeutil.ParseLegacySchedule(t.in)
if t.errStr != "" {
c.Check(err, ErrorMatches, t.errStr, Commentf("%q returned unexpected error: %s", t.in, err))
} else {
c.Check(err, IsNil, Commentf("%q returned error: %s", t.in, err))
c.Check(schedule, DeepEquals, t.expected, Commentf("%q failed", t.in))
}
}
}
func parse(c *C, s string) (time.Duration, time.Duration) {
l := strings.Split(s, "-")
c.Assert(l, HasLen, 2)
a, err := time.ParseDuration(l[0])
c.Assert(err, IsNil)
b, err := time.ParseDuration(l[1])
c.Assert(err, IsNil)
return a, b
}
const (
maxDuration = 60 * 24 * time.Hour
)
func (ts *timeutilSuite) TestLegacyScheduleNext(c *C) {
const shortForm = "2006-01-02 15:04"
for _, t := range []struct {
schedule string
last string
now string
next string
}{
{
// daily schedule, missed one window
// -> run next daily window
schedule: "9:00-11:00/21:00-23:00",
last: "2017-02-05 22:00",
now: "2017-02-06 20:00",
next: "1h-3h",
},
{
// daily schedule, used one window
// -> run next daily window
schedule: "9:00-11:00/21:00-23:00",
last: "2017-02-06 10:00",
now: "2017-02-06 20:00",
next: "1h-3h",
},
{
// daily schedule, missed all todays windows
// run tomorrow
schedule: "9:00-11:00/21:00-22:00",
last: "2017-02-04 21:30",
now: "2017-02-06 23:00",
next: "10h-12h",
},
{
// single daily schedule, already updated today
schedule: "9:00-11:00",
last: "2017-02-06 09:30",
now: "2017-02-06 10:00",
next: "23h-25h",
},
{
// single daily schedule, already updated today
// (at exactly the edge)
schedule: "9:00-11:00",
last: "2017-02-06 09:00",
now: "2017-02-06 09:00",
next: "24h-26h",
},
{
// single daily schedule, last update a day ago
// now is within the update window so randomize
// (run within remaining time delta)
schedule: "9:00-11:00",
last: "2017-02-05 09:30",
now: "2017-02-06 10:00",
next: "0-55m",
},
{
// multi daily schedule, already updated today
schedule: "9:00-11:00/21:00-22:00",
last: "2017-02-06 21:30",
now: "2017-02-06 23:00",
next: "10h-12h",
},
{
// daily schedule, very small window
schedule: "9:00-9:03",
last: "2017-02-05 09:02",
now: "2017-02-06 08:58",
next: "2m-5m",
},
{
// daily schedule, zero window
schedule: "9:00-9:00",
last: "2017-02-05 09:02",
now: "2017-02-06 08:58",
next: "2m-2m",
},
} {
last, err := time.ParseInLocation(shortForm, t.last, time.Local)
c.Assert(err, IsNil)
fakeNow, err := time.ParseInLocation(shortForm, t.now, time.Local)
c.Assert(err, IsNil)
restorer := timeutil.MockTimeNow(func() time.Time {
return fakeNow
})
defer restorer()
sched, err := timeutil.ParseLegacySchedule(t.schedule)
c.Assert(err, IsNil)
minDist, maxDist := parse(c, t.next)
next := timeutil.Next(sched, last, maxDuration)
c.Check(next >= minDist && next <= maxDist, Equals, true, Commentf("invalid distance for schedule %q with last refresh %q, now %q, expected %v, got %v", t.schedule, t.last, t.now, t.next, next))
}
}
func (ts *timeutilSuite) TestParseSchedule(c *C) {
for _, t := range []struct {
in string
expected []*timeutil.Schedule
errStr string
}{
// invalid
{"", nil, `cannot parse "": not a valid fragment`},
{"invalid-11:00", nil, `cannot parse "invalid-11:00": not a valid time`},
{"9:00-11:00/invalid", nil, `cannot parse "9:00-11:00/invalid": not a valid interval`},
{"9:00-11:00/0", nil, `cannot parse "9:00-11:00/0": not a valid interval`},
{"09:00-25:00", nil, `cannot parse "09:00-25:00": not a valid time`},
{"09:00-24:30", nil, `cannot parse "09:00-24:30": not a valid time`},
{"mon-01:00", nil, `cannot parse "mon-01:00": not a valid time`},
{"9:00-mon@11:00", nil, `cannot parse "9:00-mon@11:00": not a valid time`},
{"9:00,mon", nil, `cannot parse "mon": invalid schedule fragment`},
{"mon~wed", nil, `cannot parse "mon~wed": "mon~wed" is not a valid weekday`},
{"mon--wed", nil, `cannot parse "mon--wed": invalid week span`},
{"mon-wed/2,,9:00", nil, `cannot parse "mon-wed/2": "wed/2" is not a valid weekday`},
{"mon..wed", nil, `cannot parse "mon..wed": "mon..wed" is not a valid weekday`},
{"mon9,9:00", nil, `cannot parse "mon9": "mon9" is not a valid weekday`},
{"mon0,9:00", nil, `cannot parse "mon0": "mon0" is not a valid weekday`},
{"mon5-mon1,9:00", nil, `cannot parse "mon5-mon1": unsupported schedule`},
{"mon%,9:00", nil, `cannot parse "mon%": "mon%" is not a valid weekday`},
{"foo2,9:00", nil, `cannot parse "foo2": "foo2" is not a valid weekday`},
{"9:00---11:00", nil, `cannot parse "9:00---11:00": not a valid time`},
{"9:00-11:00/3/3/3", nil, `cannot parse "9:00-11:00/3/3/3": not a valid interval`},
{"9:00-11:00///3", nil, `cannot parse "9:00-11:00///3": not a valid interval`},
{"9:00-9:00-10:00/3", nil, `cannot parse "9:00-9:00-10:00/3": not a valid time`},
{"9:00,,,9:00-10:00/3", nil, `cannot parse ",9:00-10:00/3": not a valid fragment`},
{",,,", nil, `cannot parse "": not a valid fragment`},
{",,", nil, `cannot parse "": not a valid fragment`},
{":", nil, `cannot parse ":": not a valid time`},
{"-", nil, `cannot parse "-": "" is not a valid weekday`},
{"-/4", nil, `cannot parse "-/4": "" is not a valid weekday`},
{"~/4", nil, `cannot parse "~/4": "~/4" is not a valid weekday`},
// valid
{
in: "9:00-11:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}}}}},
}, {
in: "9:00-11:00/2",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}, Split: 2}}}},
}, {
in: "mon,9:00-11:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
}},
}, {
in: "fri,mon,9:00-11:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Friday}, End: timeutil.Week{Weekday: time.Friday}},
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
}},
}, {
in: "9:00-11:00,,20:00-22:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}}},
}, {
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 20}, End: timeutil.Clock{Hour: 22}}}},
},
}, {
in: "mon,9:00-11:00,,wed,22:00-23:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
}, {
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 22}, End: timeutil.Clock{Hour: 23}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Wednesday}, End: timeutil.Week{Weekday: time.Wednesday}}},
}},
}, {
in: "mon,9:00,10:00,14:00,15:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 9}},
{Start: timeutil.Clock{Hour: 10}, End: timeutil.Clock{Hour: 10}},
{Start: timeutil.Clock{Hour: 14}, End: timeutil.Clock{Hour: 14}},
{Start: timeutil.Clock{Hour: 15}, End: timeutil.Clock{Hour: 15}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
}},
}, {
in: "mon,wed",
expected: []*timeutil.Schedule{{
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}},
{Start: timeutil.Week{Weekday: time.Wednesday}, End: timeutil.Week{Weekday: time.Wednesday}}},
}},
}, {
// same as above
in: "mon,,wed",
expected: []*timeutil.Schedule{{
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday}}},
}, {
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Wednesday}, End: timeutil.Week{Weekday: time.Wednesday}}}},
},
}, {
// but not the same as this one
in: "mon-wed",
expected: []*timeutil.Schedule{{
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Wednesday}}},
}},
}, {
in: "mon-wed,fri,9:00-11:00/2",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}, Split: 2},
},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Wednesday}},
{Start: timeutil.Week{Weekday: time.Friday}, End: timeutil.Week{Weekday: time.Friday}},
},
}},
}, {
in: "9:00~11:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 11}, Spread: true}},
}},
}, {
in: "9:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 9}}},
}},
}, {
in: "mon1,9:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 9}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday, Pos: 1}, End: timeutil.Week{Weekday: time.Monday, Pos: 1}}},
}},
}, {
in: "00:00-24:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 0}, End: timeutil.Clock{Hour: 24}}},
}},
}, {
in: "23:00-01:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 23}, End: timeutil.Clock{Hour: 1}},
},
}},
}, {
in: "fri-mon",
expected: []*timeutil.Schedule{{
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Friday}, End: timeutil.Week{Weekday: time.Monday}}},
}},
}, {
in: "mon-mon2,9:00",
expected: []*timeutil.Schedule{{
ClockSpans: []timeutil.ClockSpan{
{Start: timeutil.Clock{Hour: 9}, End: timeutil.Clock{Hour: 9}}},
WeekSpans: []timeutil.WeekSpan{
{Start: timeutil.Week{Weekday: time.Monday}, End: timeutil.Week{Weekday: time.Monday, Pos: 2}}},
}},
},
} {
c.Logf("trying %+v", t)
schedule, err := timeutil.ParseSchedule(t.in)
if t.errStr != "" {
c.Check(err, ErrorMatches, t.errStr, Commentf("%q returned unexpected error: %s", t.in, err))
} else {
c.Check(err, IsNil, Commentf("%q returned error: %s", t.in, err))
c.Check(schedule, DeepEquals, t.expected, Commentf("%q failed", t.in))
}
}
}
func (ts *timeutilSuite) TestScheduleNext(c *C) {
const shortForm = "2006-01-02 15:04"
for _, t := range []struct {
schedule string
last string
now string
next string
randomized bool
}{
{
schedule: "mon,10:00,,fri,15:00",
// sun 22:00
last: "2017-02-05 22:00",
// mon 9:00
now: "2017-02-06 9:00",
next: "1h-1h",
}, {
// first monday of the month, at 10:00
schedule: "mon1,10:00",
// Sun 22:00
last: "2017-02-05 22:00",
// Mon 9:00
now: "2017-02-06 9:00",
next: "1h-1h",
}, {
// first Monday of the month, at 10:00
schedule: "mon1,10:00",
// first Monday of the month, 10:00
last: "2017-02-06 10:00",
// first Monday of the month, 11:00, right after
// 'previous first Monday' run
now: "2017-02-06 11:00",
// expecting March, 6th, 10:00, 27 days and 23 hours
// from now
next: "671h-671h",
}, {
// second Monday of the month, at 10:00
schedule: "mon2,10:00",
// first Monday of the month, 10:00
last: "2017-02-06 10:00",
// first Monday of the month, 11:00, right after
// 'previous first Monday' run
now: "2017-02-06 11:00",
// expecting February, 13, 10:00, 6 days and 23 hours
// from now
next: "167h-167h",
}, {
// last Monday of the month, at 10:00
schedule: "mon5,10:00",
// first Monday of the month, 10:00
last: "2017-02-06 10:00",
// first Monday of the month, 11:00, right after
// 'previous first Monday' run
now: "2017-02-06 11:00",
// expecting February, 27th, 10:00, 20 days and 23 hours
// from now
next: "503h-503h",
}, {
// (deprecated syntax, interpreted as mon1-tue)
// from the first Monday of the month to the second Tuesday of
// the month, at 10:00
schedule: "mon1-tue2,10:00",
// Monday, 10:00
last: "2017-02-06 10:00",
// Tuesday, the day after the first Monday of the month
now: "2017-02-07 11:00",
// expecting to run on 03.06.2017
next: "647h-647h",
}, {
// from the first Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue,10:00",
last: "2017-02-01 10:00",
// Sunday, 10:00
now: "2017-02-05 10:00",
// expecting to run the next day at 10:00
next: "24h-24h",
}, {
// from the first Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue,10:00",
// Tuesday, 10:00
last: "2017-02-14 22:00",
// Thursday, 10:00
now: "2017-02-16 10:00",
// expecting to run in 18 days
next: "432h-432h",
}, {
// from the first Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue,10:00",
// Sunday, 22:00
last: "2017-02-05 22:00",
// first Monday of the month
now: "2017-02-06 11:00",
// expecting to run the next day at 10:00
next: "23h-23h",
}, {
// from the first Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue,10:00-12:00",
// Sunday, 22:00
last: "2017-02-05 22:00",
// first Monday of the month, within the update window
now: "2017-02-06 11:00",
// expecting to run now
next: "0h-0h",
}, {
// from the first Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue,10:00~12:00",
// Sunday, 22:00
last: "2017-02-05 22:00",
// first Monday of the month, within the update window
now: "2017-02-06 11:00",
// expecting to run now
next: "0h-1h",
// since we're in update window we'll run now regardless
// of 'spreading'
randomized: false,
}, {
schedule: "mon,10:00~12:00,,fri,15:00",
last: "2017-02-05 22:00",
now: "2017-02-06 9:00",
next: "1h-3h",
randomized: true,
}, {
schedule: "mon,10:00-12:00,,fri,15:00",
last: "2017-02-06 12:00",
// tue 12:00
now: "2017-02-07 12:00",
// 3 days and 3 hours from now
next: "75h-75h",
}, {
// randomized between 10:00 and 12:00
schedule: "mon,10:00~12:00",
// sun 22:00
last: "2017-02-05 22:00",
// mon 9:00
now: "2017-02-06 9:00",
next: "1h-3h",
randomized: true,
}, {
// Friday to Monday, 10am
schedule: "fri-mon,10:00",
// sun 22:00
last: "2017-02-05 22:00",
// mon 9:00
now: "2017-02-06 9:00",
next: "1h-1h",
}, {
// Friday to Monday, 10am
schedule: "fri-mon,10:00",
// mon 10:00
last: "2017-02-06 10:00",
// mon 10:00
now: "2017-02-06 10:00",
// 4 days from now
next: "96h-96h",
}, {
// Wednesday to Friday, 10am
schedule: "wed-fri,10:00",
// mon 10:00
last: "2017-02-06 10:00",
// mon 10:00
now: "2017-02-06 10:00",
// 2 days from now
next: "48h-48h",
}, {
// randomized, once a day
schedule: "0:00~24:00",
// sun 22:00
last: "2017-02-05 22:00",
// mon 9:00
now: "2017-02-05 23:00",
next: "1h-25h",
randomized: true,
}, {
// randomized, once a day
schedule: "0:00~24:00",
// mon 10:00
last: "2017-02-06 10:00",
// mon 11:00
now: "2017-02-06 11:00",
// sometime the next day
next: "13h-37h",
randomized: true,
}, {
// during the night, 23:00-1:00
schedule: "23:00~1:00",
// mon 10:00
last: "2017-02-06 10:00",
// mon 11:00
now: "2017-02-06 22:00",
// sometime over the night
next: "1h-3h",
randomized: true,
}, {
// during the night, 23:00-1:00
schedule: "23:00~1:00",
// Mon 23:00
last: "2017-02-06 23:00",
// Tue 0:00
now: "2017-02-07 00:00",
// sometime over the night
next: "23h-25h",
randomized: true,
}, {
// twice between 9am and 11am
schedule: "9:00-11:00/2",
// last attempt at the beginning of window
last: "2017-02-06 9:00",
// sometime between 10am and 11am
now: "2017-02-06 9:30",
next: "30m-90m",
}, {
// 2 ranges
schedule: "9:00-10:00,10:00-11:00",
// last attempt at the beginning of window
last: "2017-02-06 9:01",
// next one at 10am
now: "2017-02-06 9:30",
next: "30m-30m",
}, {
// twice, at 9am and at 2pm
schedule: "9:00,14:00",
// last right after scheduled time window
last: "2017-02-06 9:01",
// next one at 2pm
now: "2017-02-06 9:30",
next: "270m-270m",
}, {
// 2 ranges, reversed order in spec
schedule: "10:00~11:00,9:00-10:00",
// last attempt at the beginning of window
last: "2017-02-06 9:01",
// sometime between 10am and 11am
now: "2017-02-06 9:30",
next: "30m-90m",
randomized: true,
}, {
// first Wednesday at 13:00
schedule: "wed1,13:00",
now: "2018-07-30 9:00",
// yesterday
last: "2018-07-29 13:00",
// next one on 2018-08-01 13:00
next: "52h-52h",
}, {
// October 2019
// Su Mo Tu We Th Fr Sa
// 29 30| 1 2 3 4 5
// 6 7 8 9 10 11 12
// 13 14 15 16 17 18 19
// 20 21 22 23 24 25 26
// 27 28 29 30 31
// first Monday to the following Wednesday of the month, in Oct
// 2019, matches 07.10-09.10
schedule: "mon1-wed,9:00-13:00",
now: "2019-09-30 9:00",
// yesterday
last: "2019-09-30 9:00",
// next one on 2019-10-07 9:00
next: "168h-168h",
}, {
// first Monday to the following Wednesday of the month, in Oct
// 2019, matches 30.09-04.10
schedule: "mon-fri1,9:00-13:00",
now: "2019-09-29 9:00",
last: "2019-09-29 9:00",
// next one on 2019-09-30 9:00
next: "24h-24h",
}, {
// most trivial case
schedule: "21:00-22:00",
now: "2019-09-29 8:00",
last: "2019-09-28 21:05",
// next one on 2019-09-29 at 21:00
next: "13h-13h",
},
} {
c.Logf("trying %+v", t)
last, err := time.ParseInLocation(shortForm, t.last, time.Local)
c.Assert(err, IsNil)
fakeNow, err := time.ParseInLocation(shortForm, t.now, time.Local)
c.Assert(err, IsNil)
restorer := timeutil.MockTimeNow(func() time.Time {
return fakeNow
})
defer restorer()
sched, err := timeutil.ParseSchedule(t.schedule)
c.Assert(err, IsNil)
// keep track of previous result for tests where event time is
// randomized
previous := time.Duration(0)
calls := 2
for i := 0; i < calls; i++ {
next := timeutil.Next(sched, last, maxDuration)
if t.randomized {
c.Check(next, Not(Equals), previous)
} else if previous != 0 {
// not randomized and not the first run
c.Check(next, Equals, previous)
}
c.Logf("next: %v", next)
minDist, maxDist := parse(c, t.next)
c.Check(next >= minDist && next <= maxDist,
Equals, true,
Commentf("invalid distance for schedule %q with last refresh %q, now %q, expected %v, got %v, date %s",
t.schedule, t.last, t.now, t.next, next, fakeNow.Add(next)))
previous = next
}
}
}
func (ts *timeutilSuite) TestScheduleIncludes(c *C) {
const shortForm = "2006-01-02 15:04:05"
for _, t := range []struct {
schedule string
now string
expecting bool
}{
{
schedule: "mon,10:00,,fri,15:00",
// mon 9:00
now: "2017-02-06 9:00:00",
expecting: false,
}, {
// first monday of the month, at 10:00
schedule: "mon1,10:00",
// Mon 10:00:00
now: "2017-02-06 10:00:00",
expecting: true,
}, {
// first monday of the month, at 10:00
schedule: "mon1,10:00",
// Mon 10:00:45
now: "2017-02-06 10:00:45",
expecting: true,
}, {
// first monday of the month, at 10:00
schedule: "mon1,10:00",
// Mon 10:01
now: "2017-02-06 10:01:00",
expecting: false,
}, {
// last Monday of the month, at 10:00
schedule: "mon5,10:00-11:00",
// first Monday of the month, 11:00, right after
// 'previous first Monday' run
now: "2017-02-27 10:59:20",
expecting: true,
}, {
// (deprecated syntax)
// from first Monday of the month to the second Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue2,10:00-12:00",
// Thursday, 11:10
now: "2017-02-09 11:10:00",
expecting: false,
}, {
// from first Monday of the month to the following Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue,10:00~12:00",
// Thursday, 11:10
now: "2017-02-02 11:10:00",
expecting: false,
}, {
// from first Monday of the month to the following Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue,10:00~12:00",
// Monday, 11:10
now: "2017-02-06 11:10:00",
expecting: true,
}, {
// from first Monday of the month to the following Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue,10:00~12:00",
// Thursday, 11:10
now: "2017-02-16 11:10:00",
expecting: false,
}, {
// from first Monday of the month to the following Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue,10:00~12:00",
// Thursday, 11:10
now: "2017-03-06 11:10:00",
expecting: true,
}, {
// from first Monday of the month to the following Tuesday of
// the month, at 10:00 to 12:00
schedule: "mon1-tue,10:00~12:00",
// Thursday, 11:10
now: "2017-02-09 11:10:00",
expecting: false,
}, {
// from first Tuesday of the month to the following Monday of
// the month, at 10:00 to 12:00
schedule: "tue1-mon,10:00~12:00",
// Thursday, 11:10
now: "2017-02-09 11:10:00",
expecting: true,
}, {
// (deprecated syntax)
// from 4th Monday of the month to the following Wednesday of
// the month, at 10:00 to 12:00
schedule: "mon4-wed5,10:00~12:00",
// Schedule ends up being Feb 27 - Mar 01 2017
now: "2017-03-02 11:10:00",
expecting: false,
}, {
// from last Monday of the month to the following Wednesday of
// the month, at 10:00 to 12:00
schedule: "mon5-wed,10:00~12:00",
// Schedule ends up being Feb 27 - Mar 01 2017
now: "2017-03-01 11:10:00",
expecting: true,
}, {
// from last Monday of the month to the following Wednesday of
// the month, at 10:00 to 12:00
schedule: "mon5-wed,10:00~12:00",
// Schedule ends up being Feb 27 - Mar 01 2017
now: "2017-03-02 11:10:00",
expecting: false,
}, {
// (deprecated syntax)
// from last Monday of the month to the following Tuesday of
// the month, at 10:00
schedule: "mon1-tue2,10:00~12:00",
// Sunday, 11:10
now: "2017-02-05 11:10:00",
expecting: false,
}, {
// twice between 9am and 11am
schedule: "9:00-11:00/2",
now: "2017-02-06 10:30:00",
expecting: true,
}, {
schedule: "9:00-10:00,10:00-11:00",
now: "2017-02-06 10:30:00",
expecting: true,
}, {
// every day, 23:59
schedule: "23:59",
now: "2017-02-06 23:59:59",
expecting: true,
}, {
// 2 ranges, reversed order in spec
schedule: "10:00~11:00,9:00-10:00",
// sometime between 10am and 11am
now: "2017-02-06 9:30:00",
expecting: true,
}, {
schedule: "mon1-wed,9:00-10:00",
// Tue, 9:30
now: "2019-10-08 9:30:00",
expecting: true,
}, {
schedule: "tue1,9:00-10:00",
// Tue, 9:30
now: "2019-10-01 9:30:00",
expecting: true,
},
} {
c.Logf("trying %+v", t)
now, err := time.ParseInLocation(shortForm, t.now, time.Local)
c.Assert(err, IsNil)
sched, err := timeutil.ParseSchedule(t.schedule)
c.Assert(err, IsNil)
c.Check(timeutil.Includes(sched, now), Equals, t.expecting,
Commentf("unexpected result for schedule %v and time %v", t.schedule, now))
}
}
func (ts *timeutilSuite) TestClockSpans(c *C) {
for _, t := range []struct {
clockspan string
flattenend []string
}{
{
clockspan: "23:00-01:00/2",
flattenend: []string{"23:00-00:00", "00:00-01:00"},
}, {
clockspan: "23:00-01:00/4",
flattenend: []string{"23:00-23:30", "23:30-00:00", "00:00-00:30", "00:30-01:00"},
},
} {
c.Logf("trying %+v", t)
spans, err := timeutil.ParseClockSpan(t.clockspan)
c.Assert(err, IsNil)
spanStrings := make([]string, len(t.flattenend))
flattened := spans.ClockSpans()
c.Assert(flattened, HasLen, len(t.flattenend))
for i := range flattened {
spanStrings[i] = flattened[i].String()
}
c.Assert(spanStrings, DeepEquals, t.flattenend)
}
}
func (ts *timeutilSuite) TestWeekSpans(c *C) {
const shortForm = "2006-01-02"
// July 2018 August 2018
// Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
// 1 2 3 4 5 6 7 1 2 3 4
// 8 9 10 11 12 13 14 5 6 7 8 9 10 11
// 15 16 17 18 19 20 21 12 13 14 15 16 17 18
// 22 23 24 25 26 27 28 19 20 21 22 23 24 25
// 29 30 31 26 27 28 29 30 31
for _, t := range []struct {
week string
when string
match bool
}{
{
// first Wednesday
week: "wed1",
when: "2018-08-01",
match: true,
}, {
// first Wednesday
week: "wed1",
// actually 2nd Wednesday
when: "2018-08-08",
match: false,
}, {
// second Wednesday
week: "wed2",
when: "2018-08-08",
match: true,
}, {
// first Tuesday
week: "tue1",
when: "2018-08-07",
match: true,
}, {
// first Sunday
week: "sun1",
when: "2018-07-01",
match: true,
}, {
// last Tuesday
week: "tue5",
when: "2018-07-31",
match: true,
}, {
// last Tuesday
week: "tue5",
when: "2018-07-24",
match: false,
}, {
// last Thursday
week: "thu5",
when: "2018-07-26",
match: true,
}, {
// using deprecated syntax
// first Monday (06.08) to first Friday (03.08), see August calendar above
// includes: 01.08-03.08 and 06.08-07.08
week: "mon1-fri1",
// Wednesday
when: "2018-08-01",
match: false,
}, {
// using deprecated syntax
// first Monday (06.08) to first Friday (03.08), see August calendar above
week: "mon1-fri",
// Tuesday
when: "2018-08-07",
match: true,
}, {
// first Monday (06.08) to first Friday (03.08), see August calendar above
week: "mon1-fri",
// Thursday
when: "2018-08-08",
match: true,
}, {
// second Monday (13.08) to second Friday (10.08), see August calendar above
// includes: 13.08-14.08 and 08.08-10.08
week: "mon2-fri",
// Thursday
when: "2018-08-13",
match: true,
}, {
// second Monday (13.08) to second Friday (10.08), see August calendar above
week: "mon2-fri",
// Thursday
when: "2018-08-13",
match: true,
}, {
// first Friday (03.08) to the following Monday (06.08), see August calendar above
// includes: 03.08-06.08
week: "fri1-mon",
// Saturday
when: "2018-08-04",
match: true,
}, {
// first Friday (06.07) to the following Monday (09.07), see July calendar above
// includes: 03.07-09.07
week: "fri1-mon",
// Sunday
when: "2018-07-08",
match: true,
}, {
// first Friday (03.08) to the preceding Monday (30.07), see July. August calendar above
// includes: 30.07-03.08
week: "mon-fri1",
// Saturday
when: "2018-08-01",
match: true,
}, {
// first Friday (03.08) to the preceding Monday (30.07), see July. August calendar above
// includes: 30.07-03.08
week: "mon-fri1",
// Saturday
when: "2018-07-30",
match: true,
}, {
// 4th Friday (27.08) to the following Monday (02.08), see July. August calendar above
// includes: 27.07-02.08
week: "fri4-thu",
// Saturday
when: "2018-08-01",
match: true,
}, {
// using deprecated syntax
// first Friday (06.07) to the following Monday (09.07), see July calendar above
// includes: 03.07-09.07
week: "fri1-mon1",
// Sunday
when: "2018-07-08",
match: true,
}, {
// first Friday (06.07) to the following Monday (09.07), see July calendar above
// includes: 06.07-09.07
week: "fri1-mon",
// Sunday
when: "2018-07-15",
match: false,
}, {
// last Monday (30.07) to the following Friday (03.07), see July calendar above
// includes: 03.07-03.08
week: "mon5-fri",
// Sunday
when: "2018-07-31",
match: true,
}, {
// last Friday (27.07) to the preceding Monday (23.07), see July calendar above
// includes: 23.07-27.07
week: "mon-fri5",
// Sunday
when: "2018-07-28",
match: false,
}, {
// last Friday (27.07) to the preceding Monday (23.07), see July calendar above
// includes: 23.07-27.07
week: "mon-fri5",
// Sunday
when: "2018-07-25",
match: true,
}, {
// first Monday (2.07) to the following Monday (9.07), see July calendar above
// includes: 2.07-9.07
week: "mon1-mon",
// Tuesday
when: "2018-07-03",
match: true,
}, {
week: "mon1-mon",
// Monday (the farther edge of the span)
when: "2018-07-09",
match: true,
}, {
week: "mon1-mon",
// Tuesday
when: "2018-07-10",
match: false,
},
} {
c.Logf("trying %+v", t)
ws, err := timeutil.ParseWeekSpan(t.week)
c.Assert(err, IsNil)
when, err := time.ParseInLocation(shortForm, t.when, time.Local)
c.Assert(err, IsNil)
c.Logf("when: %v %s", when, when.Weekday())
c.Check(ws.Match(when), Equals, t.match)
}
}
func (ts *timeutilSuite) TestTimeZero(c *C) {
// test with a zero time stamp to make sure that code does not do
// anything silly
// zero time is: time is: 0001-01-01 00:00:00 +0000 UTC and ... Monday
zero := time.Time{}
c.Logf("time is: %v weekday: %v", zero, zero.Weekday())
for _, schedule := range []string{
"mon-tue,0:00-12:00",
"mon1-tue,0:00-12:00",
"mon-tue1,0:00-12:00",
} {
c.Logf("trying: %v", schedule)
sch, err := timeutil.ParseSchedule(schedule)
c.Assert(err, IsNil)
c.Check(timeutil.Includes(sch, zero), Equals, true)
c.Check(timeutil.Includes(sch, zero.Add(5*time.Hour)), Equals, true)
// wednesday
c.Check(timeutil.Includes(sch, zero.Add(2*24*time.Hour)), Equals, false)
}
}
func (ts *timeutilSuite) TestMonthNext(c *C) {
const shortForm = "2006-01-02"
for _, t := range []struct {
when, next string
}{
{"2018-07-01", "2018-08-01"},
{"2018-07-31", "2018-08-01"},
{"2018-07-20", "2018-08-01"},
{"2018-02-01", "2018-03-01"},
{"2018-02-28", "2018-03-01"},
{"2018-01-31", "2018-02-01"},
// in 2020 Feb is 29 days
{"2020-01-31", "2020-02-01"},
{"2020-02-01", "2020-03-01"},
{"2020-02-14", "2020-03-01"},
} {
when, err := time.ParseInLocation(shortForm, t.when, time.Local)
c.Assert(err, IsNil)
c.Logf("when: %v expecting: %v", when, t.next)
next := timeutil.MonthNext(when)
c.Check(next.Format(shortForm), Equals, t.next)
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。