diff --git a/common/pom.xml b/common/pom.xml index e480c387..45c296a8 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -71,6 +71,11 @@ antlr4-runtime ${antlr.version} + + ch.qos.logback + logback-classic + test + diff --git a/common/src/main/java/ctbrec/GlobalThreadPool.java b/common/src/main/java/ctbrec/GlobalThreadPool.java index aaeccf92..71e93701 100644 --- a/common/src/main/java/ctbrec/GlobalThreadPool.java +++ b/common/src/main/java/ctbrec/GlobalThreadPool.java @@ -8,7 +8,7 @@ import java.util.concurrent.Future; public class GlobalThreadPool { - private static ExecutorService threadPool = Executors.newCachedThreadPool(r -> { + private static final ExecutorService threadPool = Executors.newCachedThreadPool(r -> { Thread t = new Thread(r); t.setDaemon(true); t.setName("GlobalWorker-" + UUID.randomUUID().toString().substring(0, 8)); diff --git a/common/src/main/java/ctbrec/recorder/RecordingPreconditions.java b/common/src/main/java/ctbrec/recorder/RecordingPreconditions.java index 05a3f454..6096b8d6 100644 --- a/common/src/main/java/ctbrec/recorder/RecordingPreconditions.java +++ b/common/src/main/java/ctbrec/recorder/RecordingPreconditions.java @@ -101,7 +101,7 @@ public class RecordingPreconditions { RecordingProcess download = lowerPrioRecordingProcess.get().getRecordingProcess(); Model lowerPrioModel = download.getModel(); LOG.info("Stopping recording for {}. Prio {} < {}", lowerPrioModel.getName(), lowerPrioModel.getPriority(), model.getPriority()); - recorder.stopRecordingProcess(lowerPrioModel); + recorder.stopRecordingProcess(lowerPrioRecordingProcess.get()); } else { throw new PreconditionNotMetException("Other models have higher prio, not starting recording for " + model.getName()); } @@ -109,14 +109,17 @@ public class RecordingPreconditions { } private Optional recordingProcessWithLowerPrio(int priority) { - Model lowest = null; - for (Model m : recorder.getRecordingProcesses().keySet()) { - if (lowest == null || m.getPriority() < lowest.getPriority()) { - lowest = m; + Recording lowest = null; + int lowestPrio = Integer.MAX_VALUE; + for (Recording rec : recorder.getRecordingProcesses()) { + Model m = rec.getModel(); + if (m.getPriority() < lowestPrio) { + lowest = rec; + lowestPrio = m.getPriority(); } } - if (lowest != null && lowest.getPriority() < priority) { - return Optional.of(recorder.getRecordingProcesses().get(lowest)); + if (lowestPrio < priority) { + return Optional.of(lowest); } else { return Optional.empty(); } @@ -129,7 +132,7 @@ public class RecordingPreconditions { } private void ensureNoRecordingRunningForModel(Model model) { - if (recorder.getRecordingProcesses().containsKey(model)) { + if (recorder.isRecordingRunningForModel(model)) { throw new PreconditionNotMetException("A recording for model " + model + " is already running"); } } @@ -189,7 +192,7 @@ public class RecordingPreconditions { private void stopModelsWithLowerPrio(ModelGroup modelGroup) throws InvalidKeyException, NoSuchAlgorithmException, IOException { recorder.getCurrentlyRecording().stream() .filter(m -> modelGroup.getModelUrls().contains(m.getUrl())) - .forEach(recorder::stopRecordingProcess); + .forEach(m -> recorder.getRecordingProcessForModel(m).ifPresent(recorder::stopRecordingProcess)); } diff --git a/common/src/main/java/ctbrec/recorder/SimplifiedLocalRecorder.java b/common/src/main/java/ctbrec/recorder/SimplifiedLocalRecorder.java index 2bd34f56..846d5aa1 100644 --- a/common/src/main/java/ctbrec/recorder/SimplifiedLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/SimplifiedLocalRecorder.java @@ -41,7 +41,7 @@ public class SimplifiedLocalRecorder implements Recorder { private final ReentrantLock recorderLock = new ReentrantLock(); private final ReentrantLock modelGroupLock = new ReentrantLock(); private final RecorderHttpClient client; - private final Map recordingProcesses = Collections.synchronizedMap(new HashMap<>()); + private final List recordingProcesses = Collections.synchronizedList(new ArrayList<>()); private final RecordingManager recordingManager; private final RecordingPreconditions preconditions; @@ -88,7 +88,7 @@ public class SimplifiedLocalRecorder implements Recorder { } checkFreeSpace(); threadPoolScaler.tick(); - waitABit(1); + waitABit(100); } }).start(); } @@ -130,7 +130,6 @@ public class SimplifiedLocalRecorder implements Recorder { Thread.currentThread().interrupt(); fail(recording); } catch (ExecutionException e) { - // TODO react to different exceptions, e.g. with a retry log.error("Error while recording model {}. Stopping recording.", recording.getModel(), e); fail(recording); } @@ -149,14 +148,14 @@ public class SimplifiedLocalRecorder implements Recorder { private void removeRecordingProcess(Recording rec) { recorderLock.lock(); try { - recordingProcesses.remove(rec.getModel()); + recordingProcesses.remove(rec); } finally { recorderLock.unlock(); } } private void fail(Recording recording) { - stopRecordingProcess(recording.getModel()); + stopRecordingProcess(recording); recording.getRecordingProcess().finalizeDownload(); if (deleteIfEmpty(recording)) { return; @@ -166,6 +165,12 @@ public class SimplifiedLocalRecorder implements Recorder { } private void scheduleRecording(Recording recording, long delayInMillis) { + if (recording.getModel().isSuspended()) { + log.info("Recording process for suspended model found: {}. Stopping now", recording.getModel()); + stopRecordingProcess(recording); + submitPostProcessingJob(recording); + return; + } ScheduledFuture future = scheduler.schedule(recording.getRecordingProcess(), delayInMillis, TimeUnit.MILLISECONDS); recording.setCurrentIteration(future); recording.getSelectedResolution(); @@ -203,65 +208,71 @@ public class SimplifiedLocalRecorder implements Recorder { recording.getRecordingProcess().stop(); recording.getRecordingProcess().awaitEnd(); } + waitForRecordingsToTerminate(); log.info("Recordings have been stopped"); } - // private void fail(ScheduledFuture future, Exception e) { - // if (downloadFutureRecordingMap.containsKey(future)) { - // Recording rec = downloadFutureRecordingMap.remove(future); - // deleteIfEmpty(rec); - // removeRecordingProcess(rec); - // rec.getRecordingProcess().finalizeDownload(); - // log.error("Error while recording stream for model {}", rec.getModel(), e); - // } else { - // log.error("Error while recording stream", e); - // } - // } + private void waitForRecordingsToTerminate() { + long secondsToWait = 30; + for (int i = 0; i < secondsToWait; i++) { + if (recordingProcesses.isEmpty()) { + return; + } + + log.info("Waiting for recording processes to terminate"); + waitABit(1000); + } + log.warn("Recording processes didn't finish in {} seconds. Continuing, but some recordings might not get post-processed", secondsToWait); + } private void submitPostProcessingJob(Recording recording) { setRecordingStatus(recording, WAITING); - postProcessing.submit(() -> { - try { - setRecordingStatus(recording, State.POST_PROCESSING); - recording.getRecordingProcess().stop(); - recording.getRecordingProcess().awaitEnd(); - recording.setDirtyFlag(true); - recording.getRecordingProcess().finalizeDownload(); - recording.refresh(); - recordingManager.saveRecording(recording); - recording.postprocess(); - List postProcessors = config.getSettings().postProcessors; - PostProcessingContext ctx = createPostProcessingContext(recording); - for (PostProcessor postProcessor : postProcessors) { - if (postProcessor.isEnabled()) { - log.debug("Running post-processor: {}", postProcessor.getName()); - boolean continuePP = postProcessor.postprocess(ctx); - if (!continuePP) { - break; + try { + postProcessing.submit(() -> { + try { + setRecordingStatus(recording, State.POST_PROCESSING); + recording.getRecordingProcess().stop(); + recording.getRecordingProcess().awaitEnd(); + recording.setDirtyFlag(true); + recording.getRecordingProcess().finalizeDownload(); + recording.refresh(); + recordingManager.saveRecording(recording); + recording.postprocess(); + List postProcessors = config.getSettings().postProcessors; + PostProcessingContext ctx = createPostProcessingContext(recording); + for (PostProcessor postProcessor : postProcessors) { + if (postProcessor.isEnabled()) { + log.debug("Running post-processor: {}", postProcessor.getName()); + boolean continuePP = postProcessor.postprocess(ctx); + if (!continuePP) { + break; + } + } else { + log.debug("Skipping post-processor {} because it is disabled", postProcessor.getName()); } - } else { - log.debug("Skipping post-processor {} because it is disabled", postProcessor.getName()); + } + recording.refresh(); + if (recording.getStatus() != State.DELETED) { + setRecordingStatus(recording, State.FINISHED); + recordingManager.saveRecording(recording); + } + log.info("Post-processing finished for {}", recording.getModel().getName()); + } catch (Exception e) { + if (e instanceof InterruptedException) { // NOSONAR + Thread.currentThread().interrupt(); + } + log.error("Error while post-processing recording {}", recording, e); + recording.setStatus(State.FAILED); + try { + recordingManager.saveRecording(recording); + } catch (IOException e1) { + log.error("Couldn't update recording state for recording {}", recording, e1); } } - recording.refresh(); - if (recording.getStatus() != State.DELETED) { - setRecordingStatus(recording, State.FINISHED); - recordingManager.saveRecording(recording); - } - log.info("Post-processing finished for {}", recording.getModel().getName()); - } catch (Exception e) { - if (e instanceof InterruptedException) { // NOSONAR - Thread.currentThread().interrupt(); - } - log.error("Error while post-processing recording {}", recording, e); - recording.setStatus(State.FAILED); - try { - recordingManager.saveRecording(recording); - } catch (IOException e1) { - log.error("Couldn't update recording state for recording {}", recording, e1); - } - } - }); + }); + } catch (RejectedExecutionException e) { + log.error("Could not start post-processing for {} {}:{}. Execution rejected by thread pool", recording, recording.getModel().getSite().getName(), recording.getModel().getDisplayName()); + } } private PostProcessingContext createPostProcessingContext(Recording recording) { @@ -362,7 +373,7 @@ public class SimplifiedLocalRecorder implements Recorder { rec.setModel(model); rec.setStartDate(download.getStartTime()); rec.setSingleFile(download.isSingleFile()); - recordingProcesses.put(model, rec); + recordingProcesses.add(rec); recordingManager.add(rec); return rec; } @@ -401,15 +412,22 @@ public class SimplifiedLocalRecorder implements Recorder { throw new NoSuchElementException("Model " + model.getName() + " [" + model.getUrl() + "] not found in list of recorded models"); } - if (recordingProcesses.containsKey(model)) { - Recording rec = recordingProcesses.get(model); - rec.getRecordingProcess().stop(); + if (isRecordingRunningForModel(model)) { + getRecordingProcessForModel(model).map(Recording::getRecordingProcess).ifPresent(RecordingProcess::stop); } } finally { recorderLock.unlock(); } } + public boolean isRecordingRunningForModel(Model model) { + return recordingProcesses.stream().anyMatch(rec -> Objects.equals(rec.getModel(), model)); + } + + public Optional getRecordingProcessForModel(Model model) { + return recordingProcesses.stream().filter(rec -> Objects.equals(rec.getModel(), model)).findAny(); + } + @Override public void switchStreamSource(Model model) throws IOException { if (models.contains(model)) { @@ -419,10 +437,7 @@ public class SimplifiedLocalRecorder implements Recorder { log.debug("Switching stream source to index {} for model {}", model.getStreamUrlIndex(), model.getName()); recorderLock.lock(); try { - Recording rec = recordingProcesses.get(model); - if (rec != null) { - stopRecordingProcess(model); - } + getRecordingProcessForModel(model).ifPresent(this::stopRecordingProcess); } finally { recorderLock.unlock(); } @@ -432,14 +447,14 @@ public class SimplifiedLocalRecorder implements Recorder { } } - void stopRecordingProcess(Model model) { + void stopRecordingProcess(Recording rec) { recorderLock.lock(); try { - log.debug("Stopping recording for {} - recording found: {}", model, recordingProcesses.get(model)); - Recording rec = recordingProcesses.get(model); + var model = rec.getModel(); + log.debug("Stopping recording for {} - recording found: {}", model, rec); log.debug("Stopping download for {}", model); rec.getRecordingProcess().stop(); - recordingProcesses.remove(model); + recordingProcesses.remove(rec); } finally { recorderLock.unlock(); } @@ -448,7 +463,7 @@ public class SimplifiedLocalRecorder implements Recorder { private void stopRecordingProcesses() { recorderLock.lock(); try { - for (Recording rec : recordingProcesses.values()) { + for (Recording rec : recordingProcesses) { rec.getRecordingProcess().stop(); } } finally { @@ -508,8 +523,7 @@ public class SimplifiedLocalRecorder implements Recorder { return; } - Recording rec = recordingProcesses.get(model); - Optional.ofNullable(rec).map(Recording::getRecordingProcess).ifPresent(RecordingProcess::stop); + getRecordingProcessForModel(model).ifPresent(this::stopRecordingProcess); } catch (IOException e) { log.error("Couldn't save config", e); } finally { @@ -564,7 +578,7 @@ public class SimplifiedLocalRecorder implements Recorder { m.setMarkedForLaterRecording(mark); if (mark && getCurrentlyRecording().contains(m)) { log.debug("Stopping recording of {}", m); - stopRecordingProcess(m); + getRecordingProcessForModel(m).ifPresent(this::stopRecordingProcess); } if (!mark) { log.debug("Removing model: {}", m); @@ -670,8 +684,9 @@ public class SimplifiedLocalRecorder implements Recorder { if (e.getType() == MODEL_ONLINE) { ModelIsOnlineEvent evt = (ModelIsOnlineEvent) e; Model model = evt.getModel(); - log.trace("Model online event: {} - suspended:{} - already recording:{}", model, model.isSuspended(), recordingProcesses.containsKey(model)); - if (!isSuspended(model) && !recordingProcesses.containsKey(model)) { + log.trace("Model online event: {} - suspended:{} - already recording:{}", model, model.isSuspended(), isRecordingRunningForModel(model)); + log.trace("Recording processes: {}", recordingProcesses.size()); + if (!isSuspended(model) && !isRecordingRunningForModel(model)) { startRecordingProcess(model); } } @@ -796,7 +811,7 @@ public class SimplifiedLocalRecorder implements Recorder { return running; } - Map getRecordingProcesses() { + List getRecordingProcesses() { return recordingProcesses; } diff --git a/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java b/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java index 6da48d38..6f248b99 100644 --- a/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java @@ -4,15 +4,18 @@ import ctbrec.Config; import ctbrec.Model; import ctbrec.Settings; import ctbrec.UnknownModel; -import ctbrec.recorder.download.hls.CombinedSplittingStrategy; -import ctbrec.recorder.download.hls.NoopSplittingStrategy; -import ctbrec.recorder.download.hls.SizeSplittingStrategy; -import ctbrec.recorder.download.hls.TimeSplittingStrategy; +import ctbrec.recorder.download.hls.*; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.time.Instant; +import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import static ctbrec.recorder.download.StreamSource.UNKNOWN; + +@Slf4j public abstract class AbstractDownload implements RecordingProcess { protected Instant startTime; @@ -22,6 +25,7 @@ public abstract class AbstractDownload implements RecordingProcess { protected Config config; protected SplittingStrategy splittingStrategy; protected ExecutorService downloadExecutor; + protected int selectedResolution = UNKNOWN; @Override public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException { @@ -72,11 +76,40 @@ public abstract class AbstractDownload implements RecordingProcess { @Override public int getSelectedResolution() { - return StreamSource.UNKNOWN; + return selectedResolution; } @Override public void awaitEnd() { // do nothing per default } + + protected StreamSource selectStreamSource(List streamSources) throws ExecutionException { + if (model.getStreamUrlIndex() >= 0 && model.getStreamUrlIndex() < streamSources.size()) { + // TODO don't use the index, but the bandwidth. if the bandwidth does not match, take the closest one + log.debug("Model stream index: {}", model.getStreamUrlIndex()); + streamSources.forEach(ss -> log.debug(ss.toString())); + StreamSource source = streamSources.get(model.getStreamUrlIndex()); + log.debug("{} selected {}", model.getName(), source); + selectedResolution = source.height; + return source; + } else { + // filter out stream resolutions, which are out of range of the configured min and max + int minRes = Config.getInstance().getSettings().minimumResolution; + int maxRes = Config.getInstance().getSettings().maximumResolution; + List filteredStreamSources = streamSources.stream() + .filter(src -> src.height == 0 || src.height == UNKNOWN || minRes <= src.height) + .filter(src -> src.height == 0 || src.height == UNKNOWN || maxRes >= src.height) + .toList(); + + if (filteredStreamSources.isEmpty()) { + throw new ExecutionException(new NoStreamFoundException("No stream left in playlist")); + } else { + StreamSource source = filteredStreamSources.get(filteredStreamSources.size() - 1); + log.debug("{} selected {}", model.getName(), source); + selectedResolution = source.height; + return source; + } + } + } } diff --git a/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java b/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java index e8eb5a40..c88352a9 100644 --- a/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java +++ b/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java @@ -27,7 +27,9 @@ public interface RecordingProcess extends Callable { void postProcess(Recording recording); - int getSelectedResolution(); + default int getSelectedResolution() { + return StreamSource.UNKNOWN; + } /** * Returns the path to the recording in the filesystem as file object diff --git a/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java index d4670f34..a1313ec2 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java @@ -252,31 +252,10 @@ public abstract class AbstractHlsDownload extends AbstractDownload { for (StreamSource streamSource : streamSources) { LOG.debug("{}:{} src {}", model.getSite().getName(), model.getName(), streamSource); } - String url; - if (model.getStreamUrlIndex() >= 0 && model.getStreamUrlIndex() < streamSources.size()) { - // TODO don't use the index, but the bandwidth. if the bandwidth does not match, take the closest one - StreamSource source = streamSources.get(model.getStreamUrlIndex()); - LOG.debug("{} selected {}", model.getName(), source); - url = source.getMediaPlaylistUrl(); - selectedResolution = source.height; - } else { - // filter out stream resolutions, which are out of range of the configured min and max - int minRes = Config.getInstance().getSettings().minimumResolution; - int maxRes = Config.getInstance().getSettings().maximumResolution; - List filteredStreamSources = streamSources.stream() - .filter(src -> src.height == 0 || src.height == UNKNOWN || minRes <= src.height) - .filter(src -> src.height == 0 || src.height == UNKNOWN || maxRes >= src.height) - .toList(); + StreamSource selectedStreamSource = selectStreamSource(streamSources); + String url = selectedStreamSource.getMediaPlaylistUrl(); + selectedResolution = selectedStreamSource.height; - if (filteredStreamSources.isEmpty()) { - throw new ExecutionException(new NoStreamFoundException("No stream left in playlist")); - } else { - StreamSource source = filteredStreamSources.get(filteredStreamSources.size() - 1); - LOG.debug("{} selected {}", model.getName(), source); - url = source.getMediaPlaylistUrl(); - selectedResolution = source.height; - } - } LOG.debug("Segment playlist url {}", url); return url; } diff --git a/common/src/test/java/ctbrec/recorder/RecordingPreconditionsTest.java b/common/src/test/java/ctbrec/recorder/RecordingPreconditionsTest.java index 3c2319af..163f7f59 100644 --- a/common/src/test/java/ctbrec/recorder/RecordingPreconditionsTest.java +++ b/common/src/test/java/ctbrec/recorder/RecordingPreconditionsTest.java @@ -10,7 +10,10 @@ import java.io.IOException; import java.time.Instant; import java.time.LocalTime; import java.time.temporal.ChronoUnit; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; import java.util.concurrent.ExecutionException; import static java.time.temporal.ChronoUnit.HOURS; @@ -84,16 +87,19 @@ class RecordingPreconditionsTest { } @Test - void testRecordingAlreadyRunning() { + void testRecordingAlreadyRunning() throws IOException, ExecutionException, InterruptedException { var recorder = mock(SimplifiedLocalRecorder.class); Model model = mock(Model.class); + when(model.isOnline(true)).thenReturn(true); when(recorder.isRunning()).thenReturn(true); - Map recordingProcesses = new HashMap<>(); - recordingProcesses.put(model, new Recording()); - when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses); + Recording rec = new Recording(); + rec.setModel(model); + when(recorder.getRecordingProcesses()).thenReturn(List.of(rec)); when(model.getRecordUntil()).thenReturn(Instant.MAX); when(model.toString()).thenReturn("Mockita Boobilicious"); + when(recorder.getModels()).thenReturn(List.of(model)); + when(recorder.isRecordingRunningForModel(model)).thenReturn(true); RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config); PreconditionNotMetException ex = assertThrows(PreconditionNotMetException.class, () -> preconditions.check(model)); @@ -171,9 +177,9 @@ class RecordingPreconditionsTest { when(recorder.notEnoughSpaceForRecording()).thenReturn(false); when(recorder.getModelGroup(theOtherOne)).thenReturn(Optional.of(group)); when(recorder.getModelGroup(mockita)).thenReturn(Optional.of(group)); - Map recordingProcesses = new HashMap<>(); - recordingProcesses.put(theOtherOne, new Recording()); - when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses); + Recording recording = new Recording(); + recording.setModel(theOtherOne); + when(recorder.getRecordingProcesses()).thenReturn(List.of(recording)); RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config); @@ -251,8 +257,10 @@ class RecordingPreconditionsTest { when(recorder.isRunning()).thenReturn(true); when(recorder.getModels()).thenReturn(modelsToRecord); when(recorder.notEnoughSpaceForRecording()).thenReturn(false); - Map recordingProcesses = new HashMap<>(); - recordingProcesses.put(theOtherOne, new Recording()); + List recordingProcesses = new ArrayList<>(); + Recording rec = new Recording(); + rec.setModel(theOtherOne); + recordingProcesses.add(rec); when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses); RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config); @@ -288,7 +296,7 @@ class RecordingPreconditionsTest { when(recorder.isRunning()).thenReturn(true); when(recorder.getModels()).thenReturn(modelsToRecord); when(recorder.notEnoughSpaceForRecording()).thenReturn(false); - Map recordingProcesses = new HashMap<>(); + List recordingProcesses = new ArrayList<>(); when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses); Model theOtherOne = mock(Model.class); @@ -297,7 +305,7 @@ class RecordingPreconditionsTest { when(theOtherOne.isOnline(true)).thenReturn(true); when(theOtherOne.getUrl()).thenReturn("http://localhost/theOtherOne"); when(theOtherOne.getPriority()).thenReturn(50); - recordingProcesses.put(theOtherOne, mockRecordingProcess(theOtherOne)); + recordingProcesses.add(mockRecordingProcess(theOtherOne)); Model lowestPrio = mock(Model.class); when(lowestPrio.getRecordUntil()).thenReturn(Instant.MAX); @@ -305,11 +313,16 @@ class RecordingPreconditionsTest { when(lowestPrio.isOnline(true)).thenReturn(true); when(lowestPrio.getUrl()).thenReturn("http://localhost/lowest"); when(lowestPrio.getPriority()).thenReturn(1); - recordingProcesses.put(theOtherOne, mockRecordingProcess(lowestPrio)); + Recording lowestPrioRecording = new Recording(); + RecordingProcess recordingProcess = mock(RecordingProcess.class); + when(recordingProcess.getModel()).thenReturn(lowestPrio); + lowestPrioRecording.setRecordingProcess(recordingProcess); + lowestPrioRecording.setModel(lowestPrio); + recordingProcesses.add(lowestPrioRecording); RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config); assertDoesNotThrow(() -> preconditions.check(mockita)); - verify(recorder).stopRecordingProcess(lowestPrio); + verify(recorder).stopRecordingProcess(lowestPrioRecording); } @Test @@ -328,7 +341,7 @@ class RecordingPreconditionsTest { when(recorder.isRunning()).thenReturn(true); when(recorder.getModels()).thenReturn(modelsToRecord); when(recorder.notEnoughSpaceForRecording()).thenReturn(false); - Map recordingProcesses = new HashMap<>(); + List recordingProcesses = new ArrayList<>(); when(recorder.getRecordingProcesses()).thenReturn(recordingProcesses); RecordingPreconditions preconditions = new RecordingPreconditions(recorder, config); @@ -371,6 +384,7 @@ class RecordingPreconditionsTest { when(download.getModel()).thenReturn(model); Recording runningRecording = mock(Recording.class); when(runningRecording.getRecordingProcess()).thenReturn(download); + when(runningRecording.getModel()).thenReturn(model); return runningRecording; } }