Add timeout window when not record

This commit is contained in:
0xb00bface 2021-09-09 13:35:03 +02:00
parent c515ce7b2a
commit 3c6c495a5b
15 changed files with 509 additions and 39 deletions

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>4.5.2</version>
<version>4.5.3</version>
<relativePath>../master</relativePath>
</parent>

View File

@ -0,0 +1,258 @@
package ctbrec.ui;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.IndexRange;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TimeTextFieldTest extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(5);
root.setPadding(new Insets(5));
Label hrLabel = new Label();
Label minLabel = new Label();
Label secLabel = new Label();
TimeTextField timeTextField = new TimeTextField();
hrLabel.textProperty().bind(Bindings.format("Hours: %d", timeTextField.hoursProperty()));
minLabel.textProperty().bind(Bindings.format("Minutes: %d", timeTextField.minutesProperty()));
secLabel.textProperty().bind(Bindings.format("Seconds: %d", timeTextField.secondsProperty()));
root.getChildren().addAll(timeTextField, hrLabel, minLabel, secLabel);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class TimeTextField extends TextField {
enum Unit {
HOURS, MINUTES, SECONDS
};
private final Pattern timePattern;
private final ReadOnlyIntegerWrapper hours;
private final ReadOnlyIntegerWrapper minutes;
private final ReadOnlyIntegerWrapper seconds;
public TimeTextField() {
this("00:00:00");
}
public TimeTextField(String time) {
super(time);
timePattern = Pattern.compile("\\d\\d:\\d\\d:\\d\\d");
if (!validate(time)) {
throw new IllegalArgumentException("Invalid time: " + time);
}
hours = new ReadOnlyIntegerWrapper(this, "hours");
minutes = new ReadOnlyIntegerWrapper(this, "minutes");
seconds = new ReadOnlyIntegerWrapper(this, "seconds");
hours.bind(new TimeTextField.TimeUnitBinding(Unit.HOURS));
minutes.bind(new TimeTextField.TimeUnitBinding(Unit.MINUTES));
seconds.bind(new TimeTextField.TimeUnitBinding(Unit.SECONDS));
}
public ReadOnlyIntegerProperty hoursProperty() {
return hours.getReadOnlyProperty();
}
public int getHours() {
return hours.get();
}
public ReadOnlyIntegerProperty minutesProperty() {
return minutes.getReadOnlyProperty();
}
public int getMinutes() {
return minutes.get();
}
public ReadOnlyIntegerProperty secondsProperty() {
return seconds.getReadOnlyProperty();
}
public int getSeconds() {
return seconds.get();
}
@Override
public void appendText(String text) {
// Ignore this. Our text is always 8 characters long, we cannot append anything
}
@Override
public boolean deleteNextChar() {
boolean success = false;
// If there's a selection, delete it:
final IndexRange selection = getSelection();
if (selection.getLength() > 0) {
int selectionEnd = selection.getEnd();
this.deleteText(selection);
this.positionCaret(selectionEnd);
success = true;
} else {
// If the caret preceeds a digit, replace that digit with a zero and move the caret forward. Else just move the caret forward.
int caret = this.getCaretPosition();
if (caret % 3 != 2) { // not preceeding a colon
String currentText = this.getText();
setText(currentText.substring(0, caret) + "0" + currentText.substring(caret + 1));
success = true;
}
this.positionCaret(Math.min(caret + 1, this.getText().length()));
}
return success;
}
@Override
public boolean deletePreviousChar() {
boolean success = false;
// If there's a selection, delete it:
final IndexRange selection = getSelection();
if (selection.getLength() > 0) {
int selectionStart = selection.getStart();
this.deleteText(selection);
this.positionCaret(selectionStart);
success = true;
} else {
// If the caret is after a digit, replace that digit with a zero and move the caret backward. Else just move the caret back.
int caret = this.getCaretPosition();
if (caret % 3 != 0) { // not following a colon
String currentText = this.getText();
setText(currentText.substring(0, caret - 1) + "0" + currentText.substring(caret));
success = true;
}
this.positionCaret(Math.max(caret - 1, 0));
}
return success;
}
@Override
public void deleteText(IndexRange range) {
this.deleteText(range.getStart(), range.getEnd());
}
@Override
public void deleteText(int begin, int end) {
// Replace all digits in the given range with zero:
StringBuilder builder = new StringBuilder(this.getText());
for (int c = begin; c < end; c++) {
if (c % 3 != 2) { // Not at a colon:
builder.replace(c, c + 1, "0");
}
}
this.setText(builder.toString());
}
@Override
public void insertText(int index, String text) {
// Handle an insert by replacing the range from index to index+text.length() with text, if that results in a valid string:
StringBuilder builder = new StringBuilder(this.getText());
builder.replace(index, index + text.length(), text);
final String testText = builder.toString();
if (validate(testText)) {
this.setText(testText);
}
this.positionCaret(index + text.length());
}
@Override
public void replaceSelection(String replacement) {
final IndexRange selection = this.getSelection();
if (selection.getLength() == 0) {
this.insertText(selection.getStart(), replacement);
} else {
this.replaceText(selection.getStart(), selection.getEnd(), replacement);
}
}
@Override
public void replaceText(IndexRange range, String text) {
this.replaceText(range.getStart(), range.getEnd(), text);
}
@Override
public void replaceText(int begin, int end, String text) {
if (begin == end) {
this.insertText(begin, text);
} else {
// only handle this if text.length() is equal to the number of characters being replaced, and if the replacement results in a valid string:
if (text.length() == end - begin) {
StringBuilder builder = new StringBuilder(this.getText());
builder.replace(begin, end, text);
String testText = builder.toString();
if (validate(testText)) {
this.setText(testText);
}
this.positionCaret(end);
}
}
}
private boolean validate(String time) {
if (!timePattern.matcher(time).matches()) {
return false;
}
String[] tokens = time.split(":");
assert tokens.length == 3;
try {
int hours = Integer.parseInt(tokens[0]);
int mins = Integer.parseInt(tokens[1]);
int secs = Integer.parseInt(tokens[2]);
if (hours < 0 || hours > 23) {
return false;
}
if (mins < 0 || mins > 59) {
return false;
}
if (secs < 0 || secs > 59) {
return false;
}
return true;
} catch (NumberFormatException nfe) {
// regex matching should assure we never reach this catch block
assert false;
return false;
}
}
private final class TimeUnitBinding extends IntegerBinding {
final Unit unit;
TimeUnitBinding(Unit unit) {
this.bind(textProperty());
this.unit = unit;
}
@Override
protected int computeValue() {
// Crazy enum magic
String token = getText().split(":")[unit.ordinal()];
return Integer.parseInt(token);
}
}
}
}

View File

@ -0,0 +1,67 @@
package ctbrec.ui.controls;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.ScrollEvent;
public class TimePicker extends Spinner<LocalTime> {
public TimePicker() {
this(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
}
public TimePicker(LocalTime value) {
setValueFactory(new TimePickerValueFactory());
getValueFactory().setValue(value);
setEditable(true);
getEditor().setOnKeyReleased(this::updateValueFromInput);
getEditor().focusedProperty().addListener((obs, oldV, focused) -> {
if (Boolean.FALSE.equals(focused)) {
getEditor().setText(getValue().toString());
}
});
setOnScroll(this::onScroll);
}
private void onScroll(ScrollEvent evt) {
int d = (int) evt.getDeltaY();
int units = (int) (Math.abs(d) / evt.getMultiplierY());
if (d > 0) {
getValueFactory().increment(units);
} else {
getValueFactory().decrement(units);
}
evt.consume();
}
private void updateValueFromInput(KeyEvent evt) {
String input = getEditor().getText();
try {
LocalTime newValue = LocalTime.parse(input);
getValueFactory().setValue(newValue);
} catch (DateTimeParseException e) {
// input is invalid, we do nothing
}
}
private class TimePickerValueFactory extends SpinnerValueFactory<LocalTime> {
@Override
public void decrement(int steps) {
LocalTime time = Optional.ofNullable(getValue()).orElse(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
setValue(time.minusMinutes(steps));
}
@Override
public void increment(int steps) {
LocalTime time = Optional.ofNullable(getValue()).orElse(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
setValue(time.plusMinutes(steps));
}
}
}

View File

@ -1,6 +1,7 @@
package ctbrec.ui.settings;
import java.io.IOException;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -13,9 +14,11 @@ import ctbrec.Settings;
import ctbrec.StringUtil;
import ctbrec.ui.controls.DirectorySelectionBox;
import ctbrec.ui.controls.ProgramSelectionBox;
import ctbrec.ui.controls.TimePicker;
import ctbrec.ui.controls.range.DiscreteRange;
import ctbrec.ui.controls.range.RangeSlider;
import ctbrec.ui.settings.api.ExclusiveSelectionProperty;
import ctbrec.ui.settings.api.LocalTimeProperty;
import ctbrec.ui.settings.api.Preferences;
import ctbrec.ui.settings.api.PreferencesStorage;
import ctbrec.ui.settings.api.Setting;
@ -82,6 +85,8 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
return createDirectorySelector(setting);
} else if (prop instanceof SimpleFileProperty) {
return createFileSelector(setting);
} else if (prop instanceof LocalTimeProperty) {
return createTimeSelector(setting);
} else if (prop instanceof IntegerProperty) {
return createIntegerProperty(setting);
} else if (prop instanceof LongProperty) {
@ -212,6 +217,23 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
return directorySelector;
}
private Node createTimeSelector(Setting setting) {
LocalTime time = (LocalTime) setting.getProperty().getValue();
var timePicker = new TimePicker(time);
timePicker.valueProperty().addListener((obs, o, n) -> saveValue(() -> {
var field = Settings.class.getField(setting.getKey());
LocalTime oldValue = (LocalTime) field.get(settings);
if (!Objects.equals(n, oldValue)) {
field.set(settings, n); // NOSONAR
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
config.save();
}
}));
return timePicker;
}
private Node createStringProperty(Setting setting) {
var ctrl = new TextField();
ctrl.textProperty().addListener((obs, oldV, newV) -> saveValue(() -> {

View File

@ -31,6 +31,7 @@ import ctbrec.ui.settings.api.Category;
import ctbrec.ui.settings.api.ExclusiveSelectionProperty;
import ctbrec.ui.settings.api.GigabytesConverter;
import ctbrec.ui.settings.api.Group;
import ctbrec.ui.settings.api.LocalTimeProperty;
import ctbrec.ui.settings.api.Preferences;
import ctbrec.ui.settings.api.Setting;
import ctbrec.ui.settings.api.SimpleDirectoryProperty;
@ -139,6 +140,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private SimpleBooleanProperty minimizeToTray;
private SimpleBooleanProperty showGridLinesInTables;
private SimpleIntegerProperty defaultPriority;
private LocalTimeProperty timeoutRecordingStartingAt;
private LocalTimeProperty timeoutRecordingEndingAt;
public SettingsTab(List<Site> sites, Recorder recorder) {
this.sites = sites;
@ -205,6 +208,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
minimizeToTray = new SimpleBooleanProperty(null, "minimizeToTray", settings.minimizeToTray);
showGridLinesInTables = new SimpleBooleanProperty(null, "showGridLinesInTables", settings.showGridLinesInTables);
defaultPriority = new SimpleIntegerProperty(null, "defaultPriority", settings.defaultPriority);
timeoutRecordingStartingAt = new LocalTimeProperty(null, "timeoutRecordingStartingAt", settings.timeoutRecordingStartingAt);
timeoutRecordingEndingAt = new LocalTimeProperty(null, "timeoutRecordingEndingAt", settings.timeoutRecordingEndingAt);
}
private void createGui() {
@ -243,7 +248,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Setting.of("Show grid lines in tables", showGridLinesInTables, "Show grid lines in tables").needsRestart(),
Setting.of("Fast scroll speed", fastScrollSpeed, "Makes the thumbnail overviews scroll faster with the mouse wheel").needsRestart())),
Category.of("Recorder",
Group.of("Settings", Setting.of("Recordings Directory", recordingsDir), Setting.of("Directory Structure", directoryStructure),
Group.of("Recorder", Setting.of("Recordings Directory", recordingsDir), Setting.of("Directory Structure", directoryStructure),
Setting.of("Split recordings after", splitAfter).converter(SplitAfterOption.converter()).onChange(this::splitValuesChanged),
Setting.of("Split recordings bigger than", splitBiggerThan).converter(SplitBiggerThanOption.converter())
.onChange(this::splitValuesChanged),
@ -256,6 +261,10 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Setting.of("File Extension", fileExtension, "File extension to use for recordings"),
Setting.of("Check online state every (seconds)", onlineCheckIntervalInSecs, "Check every x seconds, if a model came online"),
Setting.of("Skip online check for paused models", onlineCheckSkipsPausedModels, "Skip online check for paused models")),
Group.of("Timeout",
Setting.of("Don't record from", timeoutRecordingStartingAt),
Setting.of("Until", timeoutRecordingEndingAt)
),
Group.of("Location", Setting.of("Record Location", recordLocal).needsRestart(), Setting.of("Server", server), Setting.of("Port", port),
Setting.of("Path", path, "Leave empty, if you didn't change the servletContext in the server config"),
Setting.of("Download Filename", downloadFilename, "File name pattern for downloads"), Setting.of("", variablesHelpButton),

View File

@ -0,0 +1,13 @@
package ctbrec.ui.settings.api;
import java.time.LocalTime;
import javafx.beans.property.SimpleObjectProperty;
public class LocalTimeProperty extends SimpleObjectProperty<LocalTime> {
public LocalTimeProperty(Object bean, String name, LocalTime initialValue) {
super(bean, name, initialValue);
}
}

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>4.5.2</version>
<version>4.5.3</version>
<relativePath>../master</relativePath>
</parent>

View File

@ -10,6 +10,7 @@ import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
@ -30,6 +31,7 @@ import com.squareup.moshi.Moshi;
import ctbrec.Settings.SplitStrategy;
import ctbrec.io.FileJsonAdapter;
import ctbrec.io.LocalTimeJsonAdapter;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.io.PostProcessorJsonAdapter;
import ctbrec.io.UuidJSonAdapter;
@ -78,6 +80,7 @@ public class Config {
.add(PostProcessor.class, new PostProcessorJsonAdapter())
.add(File.class, new FileJsonAdapter())
.add(UUID.class, new UuidJSonAdapter())
.add(LocalTime.class, new LocalTimeJsonAdapter())
.build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class).lenient();
File configFile = new File(configDir, filename);
@ -239,6 +242,7 @@ public class Config {
.add(PostProcessor.class, new PostProcessorJsonAdapter())
.add(File.class, new FileJsonAdapter())
.add(UUID.class, new UuidJSonAdapter())
.add(LocalTime.class, new LocalTimeJsonAdapter())
.build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class).indent(" ");
String json = adapter.toJson(settings);

View File

@ -1,6 +1,7 @@
package ctbrec;
import java.io.File;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@ -177,6 +178,8 @@ public class Settings {
public String stripchatPassword = "";
public boolean stripchatUseXhamster = false;
public List<String> tabOrder = new ArrayList<>();
public LocalTime timeoutRecordingStartingAt = LocalTime.of(0, 0);
public LocalTime timeoutRecordingEndingAt = LocalTime.of(0, 0);
public boolean totalModelCountInTitle = false;
public boolean transportLayerSecurity = true;
public int thumbWidth = 180;

View File

@ -0,0 +1,21 @@
package ctbrec.io;
import java.io.IOException;
import java.time.LocalTime;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
public class LocalTimeJsonAdapter extends JsonAdapter<LocalTime> {
@Override
public LocalTime fromJson(JsonReader reader) throws IOException {
String timeString = reader.nextString();
return LocalTime.parse(timeString);
}
@Override
public void toJson(JsonWriter writer, LocalTime time) throws IOException {
writer.value(time.toString());
}
}

View File

@ -101,7 +101,7 @@ public class NextGenLocalRecorder implements Recorder {
recording = true;
registerEventBusListener();
preconditions = new RecordingPreconditions(this);
preconditions = new RecordingPreconditions(this, config);
LOG.debug("Recorder initialized");
LOG.info("Models to record: {}", models);
@ -286,7 +286,7 @@ public class NextGenLocalRecorder implements Recorder {
private CompletableFuture<Void> startRecordingProcess(Model model) {
return CompletableFuture.runAsync(() -> {
try {
preconditions.check(model, config);
preconditions.check(model);
LOG.info("Starting recording for model {}", model.getName());
Download download = createDownload(model);
recorderLock.lock();

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalTime;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@ -28,14 +29,15 @@ public class RecordingPreconditions {
private long lastPreconditionMessage = 0;
RecordingPreconditions(NextGenLocalRecorder recorder) {
RecordingPreconditions(NextGenLocalRecorder recorder, Config config) {
this.recorder = recorder;
this.config = config;
}
void check(Model model, Config config) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
this.config = config;
void check(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
LOG.debug("Checking preconditions for model {}", model);
ensureRecorderIsActive();
ensureNotInTimeoutPeriod();
ensureModelIsNotSuspended(model);
ensureModelIsNotMarkedForLaterRecording(model);
ensureRecordUntilIsInFuture(model);
@ -47,6 +49,21 @@ public class RecordingPreconditions {
ensureDownloadSlotAvailable(model);
}
private void ensureNotInTimeoutPeriod() {
LocalTime start = config.getSettings().timeoutRecordingStartingAt;
LocalTime end = config.getSettings().timeoutRecordingEndingAt;
if (start.equals(end)) {
return;
}
LocalTime now = LocalTime.now();
if (start.isBefore(end) && now.isAfter(start) && now.isBefore(end)) {
throw new PreconditionNotMetException("Current time is in recording timeout " + start + " - " + end);
} else if(start.isAfter(end) && !(now.isAfter(end) && now.isBefore(start))) { // NOSONAR
throw new PreconditionNotMetException("Current time is in recording timeout " + start + " - " + end);
}
}
private void ensureModelIsOnline(Model model) {
try {
if (!model.isOnline(IGNORE_CACHE)) {

View File

@ -8,6 +8,8 @@ import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -45,8 +47,8 @@ class RecordingPreconditionsTest {
NextGenLocalRecorder recorder = mock(NextGenLocalRecorder.class);
Model model = mock(Model.class);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("Recorder is not in recording mode", ex.getMessage());
}
@ -59,8 +61,8 @@ class RecordingPreconditionsTest {
when(model.isSuspended()).thenReturn(true);
when(model.toString()).thenReturn("Mockita Boobilicious");
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("Recording for model Mockita Boobilicious is suspended", ex.getMessage());
}
@ -73,8 +75,8 @@ class RecordingPreconditionsTest {
when(model.isMarkedForLaterRecording()).thenReturn(true);
when(model.toString()).thenReturn("Mockita Boobilicious");
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("Model Mockita Boobilicious is marked for later recording", ex.getMessage());
}
@ -87,8 +89,8 @@ class RecordingPreconditionsTest {
when(model.getRecordUntil()).thenReturn(Instant.now().minus(1, HOURS));
when(model.toString()).thenReturn("Mockita Boobilicious");
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertTrue(ex.getMessage().contains("Recording expired at "));
}
@ -104,8 +106,8 @@ class RecordingPreconditionsTest {
when(model.getRecordUntil()).thenReturn(Instant.MAX);
when(model.toString()).thenReturn("Mockita Boobilicious");
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("A recording for model Mockita Boobilicious is already running", ex.getMessage());
}
@ -121,8 +123,8 @@ class RecordingPreconditionsTest {
when(model.toString()).thenReturn("Mockita Boobilicious");
when(model.isOnline(true)).thenReturn(true);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("Model Mockita Boobilicious has been removed. Restarting of recording cancelled.", ex.getMessage());
modelsToRecord.add(model);
@ -130,7 +132,7 @@ class RecordingPreconditionsTest {
when(recorder.isRecording()).thenReturn(true);
when(recorder.getModels()).thenReturn(modelsToRecord);
when(recorder.enoughSpaceForRecording()).thenReturn(true);
assertDoesNotThrow(() -> preconditions.check(model, config));
assertDoesNotThrow(() -> preconditions.check(model));
}
@Test
@ -147,8 +149,8 @@ class RecordingPreconditionsTest {
when(recorder.getModels()).thenReturn(modelsToRecord);
when(recorder.enoughSpaceForRecording()).thenReturn(false);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model));
assertEquals("Not enough disk space for recording", ex.getMessage());
}
@ -185,8 +187,8 @@ class RecordingPreconditionsTest {
when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("The Other One from the same group is already recorded", ex.getMessage());
}
@ -206,8 +208,8 @@ class RecordingPreconditionsTest {
when(recorder.getModels()).thenReturn(modelsToRecord);
when(recorder.enoughSpaceForRecording()).thenReturn(true);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("Mockita Boobilicious's room is not public", ex.getMessage());
}
@ -226,15 +228,15 @@ class RecordingPreconditionsTest {
when(recorder.getModels()).thenReturn(modelsToRecord);
when(recorder.enoughSpaceForRecording()).thenReturn(true);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("Mockita Boobilicious's room is not public", ex.getMessage());
reset(mockita);
when(mockita.isOnline(true)).thenThrow(new InterruptedException());
when(mockita.getRecordUntil()).thenReturn(Instant.MAX);
when(mockita.getName()).thenReturn("Mockita Boobilicious");
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("Mockita Boobilicious's room is not public", ex.getMessage());
}
@ -264,20 +266,20 @@ class RecordingPreconditionsTest {
recordingProcesses.put(theOtherOne, new Recording());
when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("Other models have higher prio, not starting recording for Mockita Boobilicious", ex.getMessage());
settings.concurrentRecordings = -1;
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita, config));
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertEquals("Other models have higher prio, not starting recording for Mockita Boobilicious", ex.getMessage());
settings.concurrentRecordings = 0;
assertDoesNotThrow(() -> preconditions.check(mockita, config));
assertDoesNotThrow(() -> preconditions.check(mockita));
settings.concurrentRecordings = 1;
recordingProcesses.clear();
assertDoesNotThrow(() -> preconditions.check(mockita, config));
assertDoesNotThrow(() -> preconditions.check(mockita));
}
@Test
@ -316,11 +318,65 @@ class RecordingPreconditionsTest {
when(lowestPrio.getPriority()).thenReturn(1);
recordingProcesses.put(theOtherOne, mockRecordingProcess(lowestPrio));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder);
assertDoesNotThrow(() -> preconditions.check(mockita, config));
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
assertDoesNotThrow(() -> preconditions.check(mockita));
verify(recorder).stopRecordingProcess(lowestPrio);
}
@Test
void testNotInTimeoutPeriod() throws InvalidKeyException, NoSuchAlgorithmException, IOException, ExecutionException, InterruptedException {
Model mockita = mock(Model.class);
when(mockita.isOnline(true)).thenReturn(true);
when(mockita.getRecordUntil()).thenReturn(Instant.MAX);
when(mockita.getName()).thenReturn("Mockita Boobilicious");
when(mockita.getPriority()).thenReturn(100);
NextGenLocalRecorder recorder = mock(NextGenLocalRecorder.class);
List<Model> modelsToRecord = new LinkedList<>();
settings.models = modelsToRecord;
settings.timeoutRecordingStartingAt = LocalTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().plusHours(1).truncatedTo(ChronoUnit.MINUTES);
modelsToRecord.add(mockita);
when(recorder.isRecording()).thenReturn(true);
when(recorder.getModels()).thenReturn(modelsToRecord);
when(recorder.enoughSpaceForRecording()).thenReturn(true);
Map<Model, Recording> recordingProcesses = new HashMap<>();
when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses);
RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config);
PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertTrue(ex.getMessage().startsWith("Current time is in recording timeout"));
settings.timeoutRecordingStartingAt = LocalTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().minusHours(2).truncatedTo(ChronoUnit.MINUTES);
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertTrue(ex.getMessage().startsWith("Current time is in recording timeout"));
settings.timeoutRecordingStartingAt = LocalTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().minusHours(2).truncatedTo(ChronoUnit.MINUTES);
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertTrue(ex.getMessage().startsWith("Current time is in recording timeout"));
settings.timeoutRecordingStartingAt = LocalTime.now().plusHours(2).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().plusHours(1).truncatedTo(ChronoUnit.MINUTES);
ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(mockita));
assertTrue(ex.getMessage().startsWith("Current time is in recording timeout"));
settings.timeoutRecordingStartingAt = LocalTime.of(0, 0);
settings.timeoutRecordingEndingAt = LocalTime.of(0, 0);
assertDoesNotThrow(() -> preconditions.check(mockita));
settings.timeoutRecordingStartingAt = LocalTime.now().plusHours(1).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().plusHours(2).truncatedTo(ChronoUnit.MINUTES);
assertDoesNotThrow(() -> preconditions.check(mockita));
settings.timeoutRecordingStartingAt = LocalTime.now().minusHours(2).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
assertDoesNotThrow(() -> preconditions.check(mockita));
settings.timeoutRecordingStartingAt = LocalTime.now().plusHours(1).truncatedTo(ChronoUnit.MINUTES);
settings.timeoutRecordingEndingAt = LocalTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
assertDoesNotThrow(() -> preconditions.check(mockita));
}
private Recording mockRecordingProcess(Model model) {
Download download = mock(Download.class);
when(download.getModel()).thenReturn(model);

View File

@ -6,7 +6,7 @@
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<packaging>pom</packaging>
<version>4.5.2</version>
<version>4.5.3</version>
<modules>
<module>../common</module>

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>4.5.2</version>
<version>4.5.3</version>
<relativePath>../master</relativePath>
</parent>