pebble/tests/fw/services/test_cron.c
2025-01-27 11:38:16 -08:00

813 lines
22 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "clar.h"
#include "services/common/cron.h"
#include "util/size.h"
#include <pebbleos/cron.h>
#include "stubs_logging.h"
#include "stubs_mutex.h"
#include "stubs_passert.h"
#include "stubs_regular_timer.h"
#include "fake_rtc.h"
// Tests
///////////////////////////////////////////////////////////
// Thursday 2015 Nov 12, 00:00:00 GMT
static const time_t s_2015_nov12_000000_gmt = 1447286400;
// Thursday 2015 Nov 12, 12:34:56 GMT
static const time_t s_2015_nov12_123456_gmt = 1447331696;
// Saturday 2015 Dec 19, 12:34:56 GMT
static const time_t s_2015_dec19_123456_gmt = 1450528496;
// DST points
static const time_t s_2015_nov20_020000_gmt = 1447984800;
static const time_t s_2015_dec20_020000_gmt = 1450576800;
static const TimezoneInfo s_timezone_gmt = {
.tm_zone = "GMT",
.dst_id = 0,
.timezone_id = 0,
.tm_gmtoff = 0,
.dst_start = 0,
.dst_end = 0,
};
void test_cron__initialize(void) {
cron_service_init();
}
void test_cron__cleanup(void) {
cron_service_deinit();
}
static TimezoneInfo g_timezone;
static void prv_set_rtc(time_t t, const TimezoneInfo *tz_info) {
fake_rtc_init(0, t);
g_timezone = *tz_info;
time_util_update_timezone(&g_timezone);
}
static void prv_cron_callback(CronJob *job, void* data) {
job->cb_data = (void*)((uintptr_t)data + 1);
}
static void prv_clock_change(int32_t time_diff, int32_t gmt_diff, bool dst_trans) {
PebbleSetTimeEvent set_time_info = {
.utc_time_delta = time_diff,
.gmt_offset_delta = gmt_diff,
.dst_changed = dst_trans,
};
rtc_set_time(rtc_get_time() + time_diff);
g_timezone.tm_gmtoff += gmt_diff;
time_util_update_timezone(&g_timezone);
cron_service_handle_clock_change(&set_time_info);
}
void test_cron__time_change_basic(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 45,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
.clock_change_tolerance = 0,
};
CronJob *job = &test_cron;
time_t base = s_2015_nov12_123456_gmt;
prv_set_rtc(base, &s_timezone_gmt);
// 2015 Nov 12, 12:45:00
int32_t target = 1447332300;
cron_clear_all_jobs();
cl_assert_equal_i(cron_service_get_job_count(), 0);
cron_job_schedule(job);
cl_assert_equal_i((uintptr_t)job->cb_data, 0);
cl_assert_equal_i(job->cached_execute_time, target);
cl_assert_equal_i(cron_service_get_job_count(), 1);
// Mutate the execute time to see if we actually effect change.
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = 10;
prv_clock_change(0, 0, false);
cl_assert_equal_i(job->cached_execute_time, UINT32_MAX);
job->cached_execute_time = UINT32_MAX;
prv_clock_change(0, 0, true);
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
prv_clock_change(0, 1, false);
target--; // adjust for GMT offset change
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
prv_clock_change(0, 1, true);
target--; // adjust for GMT offset change
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = 0;
prv_clock_change(0, 0, false);
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = 0;
prv_clock_change(1, 0, false);
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = 1;
prv_clock_change(0, 0, false);
cl_assert_equal_i(job->cached_execute_time, UINT32_MAX);
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = 1;
prv_clock_change(1, 0, false);
cl_assert_equal_i(job->cached_execute_time, target);
job->cached_execute_time = UINT32_MAX;
job->clock_change_tolerance = UINT32_MAX;
prv_clock_change(INT32_MAX, 0, false);
cl_assert_equal_i(job->cached_execute_time, UINT32_MAX);
cron_clear_all_jobs();
}
void test_cron__time_change_instant(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 35,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
.clock_change_tolerance = 0,
};
CronJob *job = &test_cron;
time_t base = s_2015_nov12_123456_gmt;
prv_set_rtc(base, &s_timezone_gmt);
// 2015 Nov 12, 12:35:00
int32_t target = 1447331700;
cron_clear_all_jobs();
cl_assert_equal_i(cron_service_get_job_count(), 0);
cron_job_schedule(job);
cl_assert_equal_i((uintptr_t)job->cb_data, 0);
cl_assert_equal_i(job->cached_execute_time, target);
cl_assert_equal_i(cron_service_get_job_count(), 1);
// Mutate the execute time to see if we actually effect change.
job->clock_change_tolerance = 100;
prv_clock_change(10, 0, false);
cl_assert_equal_i((uintptr_t)job->cb_data, 1);
cl_assert_equal_i(job->cached_execute_time, target);
cl_assert_equal_i(cron_service_get_job_count(), 0);
cron_clear_all_jobs();
}
static void prv_basic_test(const TimezoneInfo *tz_info, CronJob *job, time_t base,
time_t offset, time_t increment, int dst_type) {
TimezoneInfo new_tz_info = *tz_info;
switch (dst_type) {
case 0:
break;
case 1:
new_tz_info.dst_start = s_2015_nov20_020000_gmt;
new_tz_info.dst_end = s_2015_dec20_020000_gmt;
break;
case 2:
new_tz_info.dst_start = 1;
new_tz_info.dst_end = INT32_MAX;
break;
}
prv_set_rtc(base, &new_tz_info);
cron_clear_all_jobs();
cl_assert_equal_i(cron_service_get_job_count(), 0);
job->cb_data = (void*)0;
cron_job_schedule(job);
cl_assert_equal_i((uintptr_t)job->cb_data, 0);
cl_assert_equal_i(job->cached_execute_time, base + offset);
cl_assert_equal_i(cron_service_get_job_count(), 1);
// Check that the timer doesn't fire early
if (offset > 0) {
fake_rtc_increment_time(increment - 1);
cron_service_wakeup();
cl_assert_equal_i((uintptr_t)job->cb_data, 0);
cl_assert_equal_i(job->cached_execute_time, base + offset);
cl_assert_equal_i(cron_service_get_job_count(), 1);
fake_rtc_increment_time(1);
} else {
fake_rtc_increment_time(increment);
}
cron_service_wakeup();
cl_assert_equal_i((uintptr_t)job->cb_data, 1);
cl_assert_equal_i(job->cached_execute_time, base + offset);
cl_assert_equal_i(cron_service_get_job_count(), 0);
}
void test_cron__1_basic(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
};
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, 0, 0, 0);
}
void test_cron__4_basic(void) {
CronJob test_cron[4] = {
{ .cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 45,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
},
{ .cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = 13,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
},
{ .cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = 12,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
},
{ .cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = 11,
.may_be_instant = true,
},
};
int timestamps[4] = {
1447332300, // 2015 Nov 12, 12:45:00 GMT
1447333200, // 2015 Nov 12, 13:00:00 GMT
1447372800, // 2015 Nov 13, 00:00:00 GMT
1448928000, // 2015 Dec 1, 00:00:00 GMT
};
prv_set_rtc(s_2015_nov12_123456_gmt, &s_timezone_gmt);
cron_clear_all_jobs();
cl_assert_equal_i(cron_service_get_job_count(), 0);
// Add the jobs in reverse order to make sure they add properly.
for (int i = 0; i < 4; i++) {
CronJob *job = &test_cron[4 - i - 1];
cron_job_schedule(job);
cl_assert_equal_i((uintptr_t)job->cb_data, 0);
cl_assert_equal_i(job->cached_execute_time, timestamps[4 - i - 1]);
cl_assert_equal_i(cron_service_get_job_count(), i+1);
}
time_t left = s_2015_nov12_123456_gmt;
for (int i = 0; i < 4; i++) {
fake_rtc_increment_time(timestamps[i] - left);
left = timestamps[i];
cron_service_wakeup();
cl_assert_equal_i(cron_service_get_job_count(), 4 - i - 1);
for (int l = 0; l < 4; l++) {
cl_assert_equal_i((uintptr_t)test_cron[l].cb_data, i >= l ? 1 : 0);
}
}
}
void test_cron__already_elapsed(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
};
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, 0, SECONDS_PER_MINUTE, 0);
}
struct {
int month, mday, hour, minute;
int8_t wday;
time_t dest_time;
} s_cron_test_info[] = {
//////// 'future' time finding
// minute
// 2015 Nov 12, 12:45:00
{ -1,-1,-1,45, WDAY_ANY, 1447332300},
// hour
// 2015 Nov 12, 13:00:00
{ -1,-1,13,-1, WDAY_ANY, 1447333200},
// hour+minute
// 2015 Nov 12, 13:45:00
{ -1,-1,13,45, WDAY_ANY, 1447335900},
// mday
// 2015 Nov 13, 00:00:00
{ -1,12,-1,-1, WDAY_ANY, 1447372800},
// mday+minute
// 2015 Nov 13, 00:45:00
{ -1,12,-1,45, WDAY_ANY, 1447375500},
// mday+hour
// 2015 Nov 13, 13:00:00
{ -1,12,13,-1, WDAY_ANY, 1447419600},
// mday+hour+minute
// 2015 Nov 13, 13:45:00
{ -1,12,13,45, WDAY_ANY, 1447422300},
// month
// 2015 Dec 1, 00:00:00
{ 11,-1,-1,-1, WDAY_ANY, 1448928000},
// month+minute
// 2015 Dec 1, 00:45:00
{ 11,-1,-1,45, WDAY_ANY, 1448930700},
// month+hour
// 2015 Dec 1, 13:00:00
{ 11,-1,13,-1, WDAY_ANY, 1448974800},
// month+hour+minute
// 2015 Dec 1, 13:45:00
{ 11,-1,13,45, WDAY_ANY, 1448977500},
// month+mday
// 2015 Dec 13, 00:00:00
{ 11,12,-1,-1, WDAY_ANY, 1449964800},
// month+mday+minute
// 2015 Dec 13, 00:45:00
{ 11,12,-1,45, WDAY_ANY, 1449967500},
// month+mday+hour
// 2015 Dec 13, 13:00:00
{ 11,12,13,-1, WDAY_ANY, 1450011600},
// month+mday+hour+minute
// 2015 Dec 13, 13:45:00
{ 11,12,13,45, WDAY_ANY, 1450014300},
//////// 'past' time finding
// minute
// 2015 Nov 12, 13:23:00
{ -1,-1,-1,23, WDAY_ANY, 1447334580},
// hour
// 2015 Nov 13, 11:00:00
{ -1,-1,11,-1, WDAY_ANY, 1447412400},
// day
// 2015 Dec 11, 00:00:00
{ -1,10,-1,-1, WDAY_ANY, 1449792000},
// month
// 2016 Oct 1, 00:00:00
{ 9,-1,-1,-1, WDAY_ANY, 1475280000},
// month+hour
// 2016 Oct 1, 12:00:00
{ 9,-1,12,-1, WDAY_ANY, 1475323200},
//////// wday time finding
// now, -Th
// 2015 Nov 13, 00:00:00
{ -1,-1,-1,-1, WDAY_ANY & ~WDAY_THURSDAY, 1447372800},
// now, -Th-Fr
// 2015 Nov 14, 00:00:00
{ -1,-1,-1,-1, WDAY_ANY & ~(WDAY_THURSDAY|WDAY_FRIDAY), 1447459200},
// now, -Th-Fr-Sa
// 2015 Nov 15, 00:00:00
{ -1,-1,-1,-1, WDAY_ANY & ~(WDAY_THURSDAY|WDAY_FRIDAY|WDAY_SATURDAY), 1447545600},
// now, -Th-Fr-Sa-Su
// 2015 Nov 16, 00:00:00
{ -1,-1,-1,-1, WDAY_MONDAY|WDAY_TUESDAY|WDAY_WEDNESDAY, 1447632000},
// now, -Th-Fr-Sa-Su-Mo
// 2015 Nov 17, 00:00:00
{ -1,-1,-1,-1, WDAY_TUESDAY|WDAY_WEDNESDAY, 1447718400},
// now, -Th-Fr-Sa-Su-Mo-Tu
// 2015 Nov 18, 00:00:00
{ -1,-1,-1,-1, WDAY_WEDNESDAY, 1447804800},
// now, -We
// now
{ -1,-1,-1,-1, WDAY_ANY & ~WDAY_WEDNESDAY, s_2015_nov12_123456_gmt},
// now, wday=0
// now
{ -1,-1,-1,-1, 0, s_2015_nov12_123456_gmt},
//////// wday+ time finding
// 19th, -Th
// 2015 Nov 20, 00:00:00
{ -1,18,-1,-1, WDAY_ANY & ~WDAY_THURSDAY, 1447977600},
// Dec, -Tu
// 2015 Dec 2, 00:00:00
{ 11,-1,-1,-1, WDAY_ANY & ~WDAY_TUESDAY, 1449014400},
//////// 'bogus' time finding
// minute
// 2015 Nov 12, 12:60:00 = 2015 Nov 12, 13:00:00
{ -1,-1,-1,60, WDAY_ANY, 1447333200},
// hour
// 2015 Nov 12, 24:00:00 = 2015 Nov 13, 00:00:00
{ -1,-1,24,-1, WDAY_ANY, 1447372800},
// mday
// 2015 Nov 33, 00:00:00 = 2015 Dec 3, 00:00:00
{ -1,32,-1,-1, WDAY_ANY, 1449100800},
// month
// 2015 Month13 1, 00:00:00 = 2016 Jan 1, 00:00:00
{ 12,-1,-1,-1, WDAY_ANY, 1451606400},
// Sentinel
{ 0,0,0,0, 0, 0},
};
void test_cron__simples(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.may_be_instant = true,
};
for (int i = 0; ; i++) {
if (s_cron_test_info[i].dest_time == 0) {
break;
}
test_cron.minute = s_cron_test_info[i].minute;
test_cron.hour = s_cron_test_info[i].hour;
test_cron.mday = s_cron_test_info[i].mday;
test_cron.month = s_cron_test_info[i].month;
test_cron.wday = s_cron_test_info[i].wday;
time_t base = s_2015_nov12_123456_gmt;
time_t advance = s_cron_test_info[i].dest_time - base;
// DST off
prv_basic_test(&s_timezone_gmt, &test_cron, base, advance, advance, 0);
// DST on
base -= SECONDS_PER_HOUR;
prv_basic_test(&s_timezone_gmt, &test_cron, base, advance, advance, 2);
}
}
void test_cron__dst_simple_to(void) {
// Nov 21st, 01:00:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 0,
.hour = 1,
.mday = 20,
.month = 10,
.may_be_instant = true,
};
// 2015 Nov 21, 00:00:00 GMT
const time_t advance = 1448064000 - s_2015_nov12_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, advance, advance, 1);
}
void test_cron__dst_simple_from(void) {
// Dec 21st, 01:00:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 0,
.hour = 1,
.mday = 20,
.month = 11,
.may_be_instant = true,
};
// 2015 Dec 21, 01:00:00 GMT
const time_t advance = 1450659600 - s_2015_dec19_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_dec19_123456_gmt, advance, advance, 1);
}
void test_cron__dst_rollover_to(void) {
// Nov 20th, 03:00:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 0,
.hour = 3,
.mday = 19,
.month = 10,
.may_be_instant = true,
};
// 2015 Nov 20, 02:00:00 GMT
const time_t advance = 1447984800 - s_2015_nov12_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, advance, advance, 1);
}
void test_cron__dst_rollover_from(void) {
// Dec 20th, 02:00:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 0,
.hour = 2,
.mday = 19,
.month = 11,
.may_be_instant = true,
};
// 2015 Dec 20, 02:00:00 GMT
time_t advance = 1450576800 - s_2015_dec19_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_dec19_123456_gmt, advance, advance, 1);
}
void test_cron__dst_hole_to(void) {
// NOTE: This behavior is SUPER weird, and it could change in the future.
// A failure in this test is not necessarily a problem.
// Nov 20th, 02:30:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 2,
.mday = 19,
.month = 10,
.may_be_instant = true,
};
// 2015 Nov 20, 02:00:00 GMT (DST start)
const time_t advance = 1447984800 - s_2015_nov12_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, advance, advance, 1);
}
void test_cron__dst_hole_from(void) {
// NOTE: This behavior is SUPER weird, and it could change in the future.
// A failure in this test is not necessarily a problem.
// Dec 20th, 01:30:00 local
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 1,
.mday = 19,
.month = 11,
.may_be_instant = true,
};
// 2015 Dec 20, 00:30:00 GMT (the 'first' 1:30)
const time_t advance = 1450571400 - s_2015_nov12_123456_gmt;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, advance, advance, 1);
}
static void prv_counting_cb(CronJob *job, void *cb_data) {
static int s_counter = 0;
job->cb_data = (void*)((uintptr_t)++s_counter);
}
#define CRON_JOB(min, hr, day, mo, callback) \
{ \
.cb = callback, \
.cb_data = (void*)0, \
.minute = min, \
.hour = hr, \
.mday = day, \
.month = mo, \
.may_be_instant = true, \
},
void test_cron__scheduled_after(void) {
CronJob jobs[] = {
CRON_JOB(CRON_MINUTE_ANY, CRON_HOUR_ANY, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_counting_cb)
CRON_JOB(CRON_MINUTE_ANY, CRON_HOUR_ANY, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(1, CRON_HOUR_ANY, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(3, CRON_HOUR_ANY, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(10, CRON_HOUR_ANY, 1, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(25, CRON_HOUR_ANY, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(55, 1, CRON_MDAY_ANY, CRON_MONTH_ANY, prv_cron_callback)
CRON_JOB(CRON_MINUTE_ANY, CRON_HOUR_ANY, 1, CRON_MONTH_ANY, prv_cron_callback)
};
CronJob new_job = {
.cb = prv_counting_cb,
.cb_data = (void*)0,
};
prv_set_rtc(s_2015_nov12_123456_gmt, &s_timezone_gmt);
cron_clear_all_jobs();
cl_assert_equal_i(cron_service_get_job_count(), 0);
for (int i = 0; i < ARRAY_LENGTH(jobs); ++i) {
cron_job_schedule(&jobs[i]);
}
cron_job_schedule_after(&jobs[0], &new_job);
cl_assert_equal_i((uintptr_t)jobs[0].cb_data, 0);
cl_assert_equal_i((uintptr_t)new_job.cb_data, 0);
cl_assert_equal_i(cron_service_get_job_count(), ARRAY_LENGTH(jobs) + 1);
fake_rtc_increment_time(0);
cron_service_wakeup();
cl_assert_equal_i((uintptr_t)jobs[0].cb_data, 1);
cl_assert_equal_i((uintptr_t)new_job.cb_data, 2);
cl_assert_equal_i(cron_service_get_job_count(), 6);
fake_rtc_increment_time(SECONDS_PER_DAY * 60);
cron_service_wakeup();
cl_assert_equal_i(cron_service_get_job_count(), 0);
}
void test_cron__offset_negative_seconds_one_wday(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 0,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = -SECONDS_PER_DAY,
.wday = WDAY_FRIDAY,
.may_be_instant = false,
};
const time_t advance = 30 * SECONDS_PER_MINUTE;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 1);
}
void test_cron__offset_negative_seconds_any_day(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 0,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = -SECONDS_PER_DAY,
.may_be_instant = false,
};
const time_t advance = 30 * SECONDS_PER_MINUTE;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 1);
}
void test_cron__offset_positive_seconds_one_wday(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 0,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = SECONDS_PER_DAY,
.wday = WDAY_THURSDAY,
.may_be_instant = false,
};
const time_t advance = 30 * SECONDS_PER_MINUTE + SECONDS_PER_DAY;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 1);
}
void test_cron__offset_positive_seconds_any_day(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 0,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = SECONDS_PER_DAY,
.may_be_instant = false,
};
const time_t advance = 30 * SECONDS_PER_MINUTE;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 1);
}
void test_cron__offset_negative_seconds_every_second(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = -SECONDS_PER_MINUTE,
.may_be_instant = true,
};
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, 0, 0, 0);
}
void test_cron__offset_positive_seconds_every_second(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = CRON_MINUTE_ANY,
.hour = CRON_HOUR_ANY,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = SECONDS_PER_MINUTE,
.may_be_instant = true,
};
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_123456_gmt, 0, 0, 0);
}
void test_cron__offset_negative_seconds_any_day_dst(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 1,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = -30 * SECONDS_PER_MINUTE,
.may_be_instant = false,
};
const time_t advance = SECONDS_PER_DAY;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 2);
}
void test_cron__offset_positive_seconds_any_day_dst(void) {
CronJob test_cron = {
.cb = prv_cron_callback,
.cb_data = (void*)0,
.minute = 30,
.hour = 0,
.mday = CRON_MDAY_ANY,
.month = CRON_MONTH_ANY,
.offset_seconds = 30 * SECONDS_PER_MINUTE,
.may_be_instant = false,
};
const time_t advance = SECONDS_PER_DAY;
prv_basic_test(&s_timezone_gmt, &test_cron, s_2015_nov12_000000_gmt, advance, advance, 2);
}