Automation: split recurring and nonrecurring time

This commit is contained in:
Milos Kozak 2019-04-02 00:05:12 +02:00
parent dc0846eab9
commit 1f62c820ca
6 changed files with 452 additions and 228 deletions

View file

@ -19,6 +19,7 @@ import butterknife.Unbinder;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerRecurringTime;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime;
public class ChooseTriggerDialog extends DialogFragment {
@ -28,8 +29,9 @@ public class ChooseTriggerDialog extends DialogFragment {
}
private static final List<Trigger> triggerDummyObjects = new ArrayList<Trigger>() {{
add(new TriggerBg());
add(new TriggerTime());
add(new TriggerBg());
add(new TriggerTime());
add(new TriggerRecurringTime());
}};
private Unbinder mUnbinder;
@ -52,7 +54,7 @@ public class ChooseTriggerDialog extends DialogFragment {
View view = inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false);
mUnbinder = ButterKnife.bind(this, view);
for(Trigger t : triggerDummyObjects) {
for (Trigger t : triggerDummyObjects) {
RadioButton radioButton = new RadioButton(getContext());
radioButton.setText(t.friendlyName());
radioButton.setTag(t);
@ -65,14 +67,14 @@ public class ChooseTriggerDialog extends DialogFragment {
checkedIndex = savedInstanceState.getInt("checkedIndex");
}
((RadioButton)mRadioGroup.getChildAt(checkedIndex)).setChecked(true);
((RadioButton) mRadioGroup.getChildAt(checkedIndex)).setChecked(true);
return view;
}
private int getCheckedIndex() {
for(int i = 0; i < mRadioGroup.getChildCount(); ++i) {
if (((RadioButton)mRadioGroup.getChildAt(i)).isChecked())
for (int i = 0; i < mRadioGroup.getChildCount(); ++i) {
if (((RadioButton) mRadioGroup.getChildAt(i)).isChecked())
return i;
}
return -1;

View file

@ -0,0 +1,301 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.StringRes;
import android.support.v4.app.FragmentManager;
import android.text.format.DateFormat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.dpro.widgets.WeekdaysPicker;
import com.google.common.base.Optional;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerRecurringTime extends Trigger {
public enum DayOfWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
private static final int[] calendarInts = new int[]{
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
Calendar.SUNDAY
};
private static final int[] fullNames = new int[]{
R.string.weekday_monday,
R.string.weekday_tuesday,
R.string.weekday_wednesday,
R.string.weekday_thursday,
R.string.weekday_friday,
R.string.weekday_saturday,
R.string.weekday_sunday
};
private static final int[] shortNames = new int[]{
R.string.weekday_monday_short,
R.string.weekday_tuesday_short,
R.string.weekday_wednesday_short,
R.string.weekday_thursday_short,
R.string.weekday_friday_short,
R.string.weekday_saturday_short,
R.string.weekday_sunday_short
};
public int toCalendarInt() {
return calendarInts[ordinal()];
}
public static DayOfWeek fromCalendarInt(int day) {
for (int i = 0; i < calendarInts.length; ++i) {
if (calendarInts[i] == day)
return values()[i];
}
return null;
}
public @StringRes
int getFullName() {
return fullNames[ordinal()];
}
public @StringRes
int getShortName() {
return shortNames[ordinal()];
}
}
private final boolean[] weekdays = new boolean[DayOfWeek.values().length];
private long lastRun;
// Recurring
private int hour;
private int minute;
private long validTo;
public TriggerRecurringTime() {
super();
setAll(false);
}
private TriggerRecurringTime(TriggerRecurringTime triggerTime) {
super();
lastRun = triggerTime.lastRun;
hour = triggerTime.hour;
minute = triggerTime.minute;
validTo = triggerTime.validTo;
for (int i = 0; i < weekdays.length; ++i) {
weekdays[i] = triggerTime.weekdays[i];
}
}
public void setAll(boolean value) {
for (DayOfWeek day : DayOfWeek.values()) {
set(day, value);
}
}
public TriggerRecurringTime set(DayOfWeek day, boolean value) {
weekdays[day.ordinal()] = value;
return this;
}
public boolean isSet(DayOfWeek day) {
return weekdays[day.ordinal()];
}
public long getLastRun() {
return lastRun;
}
@Override
public boolean shouldRun() {
if (validTo != 0 && DateUtil.now() > validTo)
return false;
Calendar c = Calendar.getInstance();
int scheduledDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
Calendar scheduledCal = DateUtil.gregorianCalendar();
scheduledCal.set(Calendar.HOUR_OF_DAY, hour);
scheduledCal.set(Calendar.MINUTE, minute);
scheduledCal.set(Calendar.SECOND, 0);
long scheduled = scheduledCal.getTimeInMillis();
if (isSet(DayOfWeek.fromCalendarInt(scheduledDayOfWeek))) {
if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) {
if (lastRun < scheduled)
return true;
}
}
return false;
}
@Override
public String toJSON() {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put("lastRun", lastRun);
for (int i = 0; i < weekdays.length; ++i) {
data.put(DayOfWeek.values()[i].name(), weekdays[i]);
}
data.put("hour", hour);
data.put("minute", minute);
data.put("validTo", validTo);
object.put("type", TriggerRecurringTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
@Override
Trigger fromJSON(String data) {
JSONObject o;
try {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
for (int i = 0; i < weekdays.length; ++i) {
weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name());
}
hour = JsonHelper.safeGetInt(o, "hour");
minute = JsonHelper.safeGetInt(o, "minute");
validTo = JsonHelper.safeGetLong(o, "validTo");
} catch (JSONException e) {
e.printStackTrace();
}
return this;
}
@Override
public int friendlyName() {
return R.string.recurringTime;
}
@Override
public String friendlyDescription() {
// TODO
return "Every ";
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_access_alarm_24dp);
}
@Override
void notifyAboutRun(long time) {
lastRun = time;
}
@Override
public Trigger duplicate() {
return new TriggerRecurringTime(this);
}
TriggerRecurringTime lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerRecurringTime validTo(long validTo) {
this.validTo = validTo;
return this;
}
TriggerRecurringTime hour(int hour) {
this.hour = hour;
return this;
}
TriggerRecurringTime minute(int minute) {
this.minute = minute;
return this;
}
private List<Integer> getSelectedDays() {
List<Integer> selectedDays = new ArrayList<>();
for (int i = 0; i < weekdays.length; ++i) {
DayOfWeek day = DayOfWeek.values()[i];
boolean selected = weekdays[i];
if (selected) selectedDays.add(day.toCalendarInt());
}
return selectedDays;
}
@Override
public View createView(final Context context, FragmentManager fragmentManager) {
LinearLayout root = (LinearLayout) super.createView(context, fragmentManager);
// TODO: Replace external tool WeekdaysPicker with a self-made GUI element
WeekdaysPicker weekdaysPicker = new WeekdaysPicker(context);
weekdaysPicker.setEditable(true);
weekdaysPicker.setSelectedDays(getSelectedDays());
weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)));
weekdaysPicker.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(weekdaysPicker);
TextView dateButton = new TextView(context);
TextView timeButton = new TextView(context);
Date runAt = new Date();
runAt.setHours(hour);
runAt.setMinutes(minute);
timeButton.setText(DateUtil.timeString(runAt));
timeButton.setOnClickListener(view -> {
Calendar calendar = Calendar.getInstance();
calendar.setTime(runAt);
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
this.hour = hourOfDay;
this.minute = minute;
runAt.setHours(this.hour);
runAt.setMinutes(this.minute);
timeButton.setText(DateUtil.timeString(runAt));
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(context)
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
android.app.FragmentManager fm = ((Activity) context).getFragmentManager();
tpd.show(fm, "Timepickerdialog");
});
root.addView(dateButton);
root.addView(timeButton);
return root;
}
}

View file

@ -1,21 +1,22 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.support.v4.app.FragmentManager;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.StringRes;
import android.support.v4.app.FragmentManager;
import android.text.format.DateFormat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.dpro.widgets.WeekdaysPicker;
import com.google.common.base.Optional;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@ -25,153 +26,24 @@ import info.nightscout.androidaps.utils.T;
public class TriggerTime extends Trigger {
public enum DayOfWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
private static final int[] calendarInts = new int[] {
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
Calendar.SUNDAY
};
private static final int[] fullNames = new int[] {
R.string.weekday_monday,
R.string.weekday_tuesday,
R.string.weekday_wednesday,
R.string.weekday_thursday,
R.string.weekday_friday,
R.string.weekday_saturday,
R.string.weekday_sunday
};
private static final int[] shortNames = new int[] {
R.string.weekday_monday_short,
R.string.weekday_tuesday_short,
R.string.weekday_wednesday_short,
R.string.weekday_thursday_short,
R.string.weekday_friday_short,
R.string.weekday_saturday_short,
R.string.weekday_sunday_short
};
public int toCalendarInt() {
return calendarInts[ordinal()];
}
public static DayOfWeek fromCalendarInt(int day) {
for(int i = 0; i < calendarInts.length; ++i) {
if (calendarInts[i] == day)
return values()[i];
}
return null;
}
public @StringRes int getFullName() {
return fullNames[ordinal()];
}
public @StringRes int getShortName() {
return shortNames[ordinal()];
}
}
private final boolean[] weekdays = new boolean[DayOfWeek.values().length];
private long runAt;
private long lastRun;
// Single execution
private long runAt;
// Recurring
private boolean recurring;
private int hour;
private int minute;
private long validTo;
public TriggerTime() {
super();
setAll(false);
}
private TriggerTime(TriggerTime triggerTime) {
super();
lastRun = triggerTime.lastRun;
runAt = triggerTime.runAt;
recurring = triggerTime.recurring;
hour = triggerTime.hour;
minute = triggerTime.minute;
validTo = triggerTime.validTo;
for(int i = 0; i < weekdays.length; ++i) {
weekdays[i] = triggerTime.weekdays[i];
}
}
public void setAll(boolean value) {
for(DayOfWeek day : DayOfWeek.values()) {
set(day, value);
}
}
public TriggerTime set(DayOfWeek day, boolean value) {
weekdays[day.ordinal()] = value;
return this;
}
public boolean isSet(DayOfWeek day) {
return weekdays[day.ordinal()];
}
public long getLastRun() {
return lastRun;
}
public long getRunAt() {
return runAt;
}
public boolean isRecurring() {
return recurring;
}
@Override
public boolean shouldRun() {
if (recurring) {
if (validTo != 0 && DateUtil.now() > validTo)
return false;
Calendar c = Calendar.getInstance();
int scheduledDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
Calendar scheduledCal = DateUtil.gregorianCalendar();
scheduledCal.set(Calendar.HOUR_OF_DAY, hour);
scheduledCal.set(Calendar.MINUTE, minute);
scheduledCal.set(Calendar.SECOND, 0);
long scheduled = scheduledCal.getTimeInMillis();
if (isSet(DayOfWeek.fromCalendarInt(scheduledDayOfWeek))) {
if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) {
if (lastRun < scheduled)
return true;
}
}
return false;
} else {
long now = DateUtil.now();
if (now >= runAt && now - runAt < T.mins(5).msecs())
return true;
return false;
}
long now = DateUtil.now();
if (now >= runAt && now - runAt < T.mins(5).msecs())
return true;
return false;
}
@Override
@ -179,15 +51,8 @@ public class TriggerTime extends Trigger {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put("lastRun", lastRun);
data.put("runAt", runAt);
data.put("recurring", recurring);
for(int i = 0; i < weekdays.length; ++i) {
data.put(DayOfWeek.values()[i].name(), weekdays[i]);
}
data.put("hour", hour);
data.put("minute", minute);
data.put("validTo", validTo);
data.put("lastRun", lastRun);
object.put("type", TriggerTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
@ -203,13 +68,6 @@ public class TriggerTime extends Trigger {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
runAt = JsonHelper.safeGetLong(o, "runAt");
recurring = JsonHelper.safeGetBoolean(o, "recurring");
for(int i = 0; i < weekdays.length; ++i) {
weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name());
}
hour = JsonHelper.safeGetInt(o, "hour");
minute = JsonHelper.safeGetInt(o, "minute");
validTo = JsonHelper.safeGetLong(o, "validTo");
} catch (JSONException e) {
e.printStackTrace();
}
@ -223,12 +81,7 @@ public class TriggerTime extends Trigger {
@Override
public String friendlyDescription() {
if (recurring) {
// TODO
return "Every ";
} else {
return MainApp.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt));
}
return MainApp.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt));
}
@Override
@ -241,63 +94,74 @@ public class TriggerTime extends Trigger {
lastRun = time;
}
@Override
public Trigger duplicate() {
return new TriggerTime(this);
}
TriggerTime lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerTime runAt(long runAt) {
this.runAt = runAt;
return this;
}
TriggerTime recurring(boolean recurring) {
this.recurring = recurring;
return this;
@Override
public Trigger duplicate() {
return new TriggerTime(this);
}
TriggerTime validTo(long validTo) {
this.validTo = validTo;
return this;
}
TriggerTime hour(int hour) {
this.hour = hour;
return this;
}
TriggerTime minute(int minute) {
this.minute = minute;
return this;
}
private List<Integer> getSelectedDays() {
List<Integer> selectedDays = new ArrayList<>();
for(int i = 0; i < weekdays.length; ++i) {
DayOfWeek day = DayOfWeek.values()[i];
boolean selected = weekdays[i];
if (selected) selectedDays.add(day.toCalendarInt());
}
return selectedDays;
public long getRunAt() {
return runAt;
}
@Override
public View createView(Context context, FragmentManager fragmentManager) {
public View createView(final Context context, FragmentManager fragmentManager) {
LinearLayout root = (LinearLayout) super.createView(context, fragmentManager);
//root.setOrientation(LinearLayout.HORIZONTAL);
// TODO: Replace external tool WeekdaysPicker with a self-made GUI element
WeekdaysPicker weekdaysPicker = new WeekdaysPicker(context);
weekdaysPicker.setEditable(true);
weekdaysPicker.setSelectedDays(getSelectedDays());
weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)));
weekdaysPicker.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
TextView dateButton = new TextView(context);
TextView timeButton = new TextView(context);
root.addView(weekdaysPicker);
dateButton.setText(DateUtil.dateString(runAt));
timeButton.setText(DateUtil.timeString(runAt));
dateButton.setOnClickListener(view -> {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(runAt);
DatePickerDialog dpd = DatePickerDialog.newInstance(
(view1, year, monthOfYear, dayOfMonth) -> {
Date eventTime = new Date(runAt);
eventTime.setYear(year - 1900);
eventTime.setMonth(monthOfYear);
eventTime.setDate(dayOfMonth);
runAt = eventTime.getTime();
dateButton.setText(DateUtil.dateString(runAt));
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
dpd.setThemeDark(true);
dpd.dismissOnPause(true);
android.app.FragmentManager fm = ((Activity) context).getFragmentManager();
dpd.show(fm, "Datepickerdialog");
});
timeButton.setOnClickListener(view -> {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(runAt);
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
Date eventTime = new Date(runAt);
eventTime.setHours(hourOfDay);
eventTime.setMinutes(minute);
runAt = eventTime.getTime();
timeButton.setText(DateUtil.timeString(eventTime));
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(context)
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
android.app.FragmentManager fm = ((Activity) context).getFragmentManager();
tpd.show(fm, "Timepickerdialog");
});
root.addView(dateButton);
root.addView(timeButton);
return root;
}
}

View file

@ -1372,6 +1372,7 @@
<string name="sms_wrongcode">Wrong code. Command cancelled.</string>
<string name="notconfigured">Not configured</string>
<string name="profileswitchcreated">Profile switch created</string>
<string name="recurringTime">Recurring time</string>
<plurals name="objective_days">
<item quantity="one">%1$d day</item>
<item quantity="other">%1$d days</item>

View file

@ -0,0 +1,72 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import com.squareup.otto.Bus;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.GregorianCalendar;
import info.AAPSMocker;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.T;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, Bus.class, DateUtil.class, GregorianCalendar.class})
public class TriggerRecurringTimeTest {
long now = 1514766900000L;
@Test
public void shouldRunTest() {
// limit by validTo
TriggerRecurringTime t = new TriggerRecurringTime().hour(1).minute(34).validTo(1);
t.setAll(true);
Assert.assertFalse(t.shouldRun());
// scheduled 1 min before
t = new TriggerRecurringTime().hour(1).minute(34);
t.setAll(true);
Assert.assertTrue(t.shouldRun());
// already run
t = new TriggerRecurringTime().hour(1).minute(34).lastRun(now - 1);
t.setAll(true);
Assert.assertFalse(t.shouldRun());
}
String timeJson = "{\"data\":{\"runAt\":1514766840000,\"THURSDAY\":false,\"lastRun\":0,\"SUNDAY\":false,\"recurring\":false,\"TUESDAY\":false,\"FRIDAY\":false,\"minute\":0,\"WEDNESDAY\":false,\"MONDAY\":false,\"hour\":0,\"SATURDAY\":false,\"validTo\":0},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerRecurringTime\"}";
@Test
public void toJSONTest() {
}
@Test
public void fromJSONTest() throws JSONException {
}
@Before
public void mock() {
AAPSMocker.mockMainApp();
AAPSMocker.mockBus();
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.now()).thenReturn(now);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(now);
when(DateUtil.gregorianCalendar()).thenReturn(calendar);
}
}

View file

@ -38,24 +38,9 @@ public class TriggerTimeTest {
t = new TriggerTime().runAt(now + T.mins(1).msecs());
Assert.assertFalse(t.shouldRun());
// limit by validTo
t = new TriggerTime().recurring(true).hour(1).minute(34).validTo(1);
t.setAll(true);
Assert.assertFalse(t.shouldRun());
// scheduled 1 min before
t = new TriggerTime().recurring(true).hour(1).minute(34);
t.setAll(true);
Assert.assertTrue(t.shouldRun());
// already run
t = new TriggerTime().recurring(true).hour(1).minute(34).lastRun(now - 1);
t.setAll(true);
Assert.assertFalse(t.shouldRun());
}
String timeJson = "{\"data\":{\"runAt\":1514766840000,\"THURSDAY\":false,\"lastRun\":0,\"SUNDAY\":false,\"recurring\":false,\"TUESDAY\":false,\"FRIDAY\":false,\"minute\":0,\"WEDNESDAY\":false,\"MONDAY\":false,\"hour\":0,\"SATURDAY\":false,\"validTo\":0},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime\"}";
String timeJson = "{\"data\":{\"runAt\":1514766840000,\"lastRun\":0},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime\"}";
@Test
public void toJSONTest() {
@ -69,7 +54,6 @@ public class TriggerTimeTest {
TriggerTime t2 = (TriggerTime) Trigger.instantiate(new JSONObject(t.toJSON()));
Assert.assertEquals(now - T.mins(1).msecs(), t2.getRunAt());
Assert.assertEquals(false, t2.isRecurring());
}
@Before